How to debug SEGV_ACCERR

前端 未结 2 1411
半阙折子戏
半阙折子戏 2020-12-14 10:43

I have an app that streams video using Kickflip and ButterflyTV libRTMP

Now for 99% percent of the time the app is working ok, but from time to time I get a native s

相关标签:
2条回答
  • 2020-12-14 11:02

    "You can store the data in a byte[]. This allows very fast access from managed code. On the native side, however, you're not guaranteed to be able to access the data without having to copy it."

    See https://developer.android.com/training/articles/perf-jni.html

    Analysis

    Some musings and things to try:

    • The code where it falls over is very generic, so probably no bug there
    • It must be the frame data has been removed/damaged/locked/moved
    • Has the Java garbage collector removed OR relocated the data ?
    • You could write detailed debug to a file, overwriting it on every frame, so you only have a small log with the last debug info.
    • send a local copy of the frame variable info (using ByteBuffer) to mRTMPMuxer.writeVideo
      Unlike regular byte buffers,in ByteBuffer the storage is not allocated on the managed heap, and can always be accessed directly from native code.

    Implementation

    //allocates memory from the native heap
    ByteBuffer data = ByteBuffer.allocateDirect(frame.getData().length);
    data.clear();
    //System.gc();
    //copy data
    data.get(frame.getData(), 0, frame.getData().length);
    //data = (frame.getData() == null) ? null : frame.getData().clone();
    int offset  = frame.getOffset();
    int size    = frame.getSize();
    int time    = frame.getTime();
    writeResult = mRTMPMuxer.writeVideo(data , offset, size, time);
    
    JNIEXPORT jint JNICALL
    Java_net_butterflytv_rtmp_1client_RTMPMuxer_writeVideo(
        JNIEnv *env,
        jobject instance,
        jobject data_, //NOT jbyteArray data_,
        jint offset,
        jint length,
        jint timestamp) 
    {
        jbyte *data = env->GetDirectBufferAddress(env, data);//GetDirectBufferAddress NOT GetByteArrayElements
        jint result = rtmp_sender_write_video_frame(data, length, timestamp, 0, 0);
        //(*env)->ReleaseByteArrayElements(env, data_, data, 0);//????
        return result;
    }
    

    Debugging

    Some code from SO Catching exceptions thrown from native code:

        static uint32_t find_start_code(uint8_t *buf, uint32_t zeros_in_startcode){
        //...
        try {
            if ((info = (buf[zeros_in_startcode] != 1)? 0: 1) == 0) return 0;//your code
        }
        // You can catch std::exception for more generic error handling
        catch (std::exception e){
            throwJavaException (env, e.what());//see method below
        }
        //...
    

    Then a new method:

        void throwJavaException(JNIEnv *env, const char *msg)
        {
         // You can put your own exception here
         jclass c = env->FindClass("java/lang/RuntimeException");
         if (NULL == c)
         {
             //B plan: null pointer ...
             c = env->FindClass("java/lang/NullPointerException");
         }
         env->ThrowNew(c, msg);
        }
    }
    

    Don't get too hung up on SEGV_ACCERR, you have a segmentation fault,SIGSEGV (caused by a program trying to read or write an illegal memory location, read in your case).
    From siginfo.h:

    SEGV_MAPERR means you tried to access an address that doesn't map to anything. SEGV_ACCERR means you tried to access an address that you don't have permission to access.

    Other

    This may be of interest:

    Q: I noticed that there was RTMP support. But a patch which remove RTMP had been merged.
    Q: Could you tell me why ?
    A: We don't think RTMP serves the mobile broadcasting use case as well as HLS,
    A: and so we don't want to dedicate our limited resources towards supporting it.

    see: https://github.com/Kickflip/kickflip-android-sdk/issues/33

    I suggest you register an issue with:
    https://github.com/Kickflip/kickflip-android-sdk/issues
    https://github.com/ButterflyTV/LibRtmp-Client-for-Android/issues

    0 讨论(0)
  • 2020-12-14 11:12

    By symptom/description of the problem, your program is most likely experiencing some sort of invalid memory access/corruption which is somehow related with multi-thread race condition scenario. From my past experience, debugging memory corruption itself is very difficult and if it is linked to multi-thread environment it becomes very very difficult. Some of my previous post might be helpful and provide some general guidelines on these topics. Please note that these posts are related to Windows/Linux and not for Android platform.

    cpp - valgrind - Invalid read of size 8

    A segmentation fault sometimes occurs when the function cvCreateFileCapture is invoked on network URL

    While reading further about similar issue and your code sinppet, I came across one post which is mentioned below:

    What does SEGV_ACCERR mean?

    Client code snippet of your application

    synchronized (mWriteFence) {
                    if (!mConnected) {
                        continue;
                    }
                    if (frame.getFrameType() == Frame.VIDEO_FRAME) {
                        writeResult = mRTMPMuxer.writeVideo(frame.getData(), frame.getOffset(), frame.getSize(), frame.getTime());
                        calcVideoFpsAndBitrate(frame.getSize());
    
                    } else if (frame.getFrameType() == Frame.AUDIO_FRAME) {
                        writeResult = mRTMPMuxer.writeAudio(frame.getData(), frame.getOffset(), frame.getSize(), frame.getTime());
                        calcAudioBitrate(frame.getSize());
                    }
    
    }
    

    From above code, it appears to me that if your application receives Frame.VIDEO_FRAME & Frame.AUDIO_FRAME in certain order it might be leading to some sort of race condition(may be async model implementation) while using the frame variable within RtmpMuxerMix.writeThread module.

    To conclude such issues:

    • we should try to read the documentation about library and its best practices and get your code reviewed. Sometime it helps to find out obvious problems in our logic.
    • We should try to reproduce this issue while running application under dynamics tools. I am not aware about such tools on Android platform. Please not that once we start running application under dynamics tools, sequence of execution gets changed and after that it is possible that we either be able to reproduce such issues very frequently or almost not be able to reproduce it.

    .

    0 讨论(0)
提交回复
热议问题