了解导致信号 11 (SIGSEGV)、代码 1 (SEGV_MAPERR) 几秒钟后出错的 Android 问题

Understanding the Android issue causing signal 11 (SIGSEGV), code 1 (SEGV_MAPERR) Error after a few seconds

我是运行传感器和位置服务,数据被传递到TraceManager文件,在那里处理它并传递到TraceCWrapper以映射到共享C库。所以,看来传感器和位置数据正常并在 TraceManager 中接收,然后传递到 TraceCWrapper,但是应用程序在几秒钟后崩溃,我得到的唯一错误行是:

A/libc:致命信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR),tid 29938 (AsyncTask #1) 中的故障地址 0x8,pid 29870 (pp.traceandroid)



public class TraceManager extends AppCompatActivity {

    private String TAG = "TraceManager";
    private int phoneAngle = 0;
    private double initialStepCalibrationOffset;
    private int initialPointingAngleDeg = 0;
    private int initialAlignmentMode = 0;
    private int startingFloorID = 0;
    private LatLng startingLatLong;
    private double startingAccuracy = 1.0;
    private Context context;
    private boolean isMagConsistentAtInit = false;
    private boolean isMagValid = true;
    private Timer callBackTimer;
    private String[] contentsStatic;
    private String[] contentsDynamic;
    private boolean isRunning = false;
    private TraceCWrapper traceCWrapper = new TraceCWrapper();
    Handler callbackHandler = new Handler();
    Runnable callbackRunnable;

    //internal use only
    private boolean _traceCDontActuallyUse;

    // The interval, in seconds, for providing trace updates.
    public ObservableDouble updateCallbackInterval = new ObservableDouble(0){
        @Override
        public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
            if(isRunning){
                stopCallbackTimer();
                startCallbackTimer();
            }

            super.addOnPropertyChangedCallback(callback);
        }
    };

    private double updateCallBackIntervalValue = updateCallbackInterval.get();

    /// A Boolean value
    public ObservableBoolean allowsBackgroundExecution = new ObservableBoolean(false){
        @Override
        public void addOnPropertyChangedCallback(@NonNull OnPropertyChangedCallback callback) {
            if(isRunning){
                stopUpdatingTrace();
                startUpdatingTrace();
            }
            super.addOnPropertyChangedCallback(callback);
        }
    };

    private boolean allowsBackgroundExecutionValue = allowsBackgroundExecution.get();


    public TraceManager(Context context){
        this.context=context;
    }


    public TraceManager(){

    }

    public void initialiseTrace(String[] mapFloors,
                                String[] initialDynamicMaps,
                                int phoneRelativeToBodyDegree, //this comes from onboarding?
                                double updateCallBackIntervalValue,
                                boolean allowsBackgroundExecutionValue,
                                double initialStepCalibrationOffset, //standard
                                String[] iBeaconUUIDs,
                                int startingFloorID,
                                LatLng startingLatLong, //this is form the starting node
                                double startingAccuracy, //
                                boolean _traceCDontActuallyUse,
                                int phoneOrientation,
                                int phoneOrientationUse,
                                boolean magntometerValid
                                ){
        this.contentsStatic = mapFloors;
        this.contentsDynamic = initialDynamicMaps;
        this.phoneAngle = phoneRelativeToBodyDegree;
        this.initialStepCalibrationOffset = initialStepCalibrationOffset;
        this.updateCallbackInterval = updateCallbackInterval;
        this.allowsBackgroundExecution = allowsBackgroundExecution;
        this.isMagValid = magntometerValid;
        if(!(iBeaconUUIDs.length <=0)){
            LocationProvider.arrayOfUUIDsToDetect = iBeaconUUIDs;
        }else{
            Log.i(TAG, "TraceManager.init: ignoring ibeaconUIDs, because it is empty. Default used");
        };

        this.startingFloorID = startingFloorID;
        this.startingLatLong = startingLatLong;
        this.startingAccuracy = startingAccuracy;
        this.initialPointingAngleDeg = phoneOrientation;
        this.initialAlignmentMode = phoneOrientationUse;

        //internal use only
        this._traceCDontActuallyUse = _traceCDontActuallyUse;
    }

//Functions
/// Broadcast Receiver to get readings from MotionProvider/service

    public void startUpdatingSensors(){
        //Start sensor service
        Intent startService = new Intent(TraceManager.this, SensorService.class);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(startService);
        } else {
            startService(startService);
        }

    }

    /// Starts the generation of trace updates.

    public void startUpdatingTrace(){
        //Start Sensors
        //startUpdatingSensors();

        //register for sensorBroadcast
        BroadcastReceiver sensorReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d(TAG, "imu Received");
                TCIMUEvent tcimuEvent = (TCIMUEvent) intent.getSerializableExtra("imu");
                traceCWrapper.provideDeviceMotion(tcimuEvent, 1, 90, RotationMode.PortraitYUp);
            }
        };
        LocalBroadcastManager.getInstance(context).registerReceiver(
                sensorReceiver, new IntentFilter("imuCreated")
        );

        //register for locationBroadcast
        //register for sensorBroadcast
        BroadcastReceiver locationReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d(TAG, "location Received");
                TCLocationEvent tcLocationEvent = (TCLocationEvent) intent.getSerializableExtra("locationCreated");
                Log.d(TAG, "Inlocation reciever");
                traceCWrapper.provideLocation(tcLocationEvent);
            }
        };
        LocalBroadcastManager.getInstance(context).registerReceiver(
                locationReceiver, new IntentFilter("locationCreated")
        );


        Log.d(TAG, "inside updating trace");
        //Start CallbackTimer
        startCallbackTimer();

    }

    private void CallbackUpdate() {

    /*    callbackRunnable = new Runnable(){
            @Override
            public void run() {
                Log.d(TAG, "calling callback");
                traceCWrapper.getLatestTraceResult();
                callbackHandler.postDelayed(this, 1000);
            }
        };*/
    }


    private void startCallbackTimer(){
        Log.d(TAG, "I get in here callback");
        callbackRunnable = new Runnable(){
            @Override
            public void run() {
                Log.d(TAG, "calling callback");
                traceCWrapper.getLatestTraceResult();
                callbackHandler.postDelayed(this, 1000);
            }
        };
        callbackHandler.postDelayed(callbackRunnable, 1000);
    }

    private void stopCallbackTimer(){
        callbackHandler.removeCallbacks(callbackRunnable);
    }



    //Calls TraceCWrapper upadate maps and passes the dynamic maps
/*    public void updateMaps(String[] dynamicMaps){
        traceCWrapper.updateMaps(dynamicMaps dynamicmaps){

        }
    }*/

    public void stopUpdatingTrace(){

        boolean stopSensors = true;
        if(stopSensors){
            stopUpdatingSensors();
        }

        //Callback Timer
        stopCallbackTimer();

        //State
        isRunning = false;

        //Trace terminate
        if (_traceCDontActuallyUse == false){
            traceCWrapper.terminate();
        }
    }

    private void stopUpdatingSensors() {

        //todo
        //stop the event bus
        //stop the service


    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void provideManualLocation(TraceManualLocation manualLocation){

        if(isRunning){
        }else{
            Log.e(TAG, "Calling provideManualLocation, but is running is set to false");
        }
        if(!_traceCDontActuallyUse){
            traceCWrapper.provideManualLocation(manualLocation);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    public void provideManualHeadingCorrection(TraceManualHeading traceManualHeading){

        if(isRunning){
        }else{
            Log.e(TAG, "Calling provideHeadingCorrection, but is running is set to false");
        }

        if (!_traceCDontActuallyUse){
            traceCWrapper.provideManualHeading(traceManualHeading);
        }

    }

    public void updateParameter(TraceCVarParameter traceCVarParameter, double value){
        if(isRunning){
        }else{
            Log.e(TAG, "Calling updateparameter, but is running is set to false");
        }
        //todo
        //callback async
    }


    //Private [START]

    boolean isInitialised = false;

    public boolean isInitialised() {
        if(!isInitialised){

        }else{
            //todo
            //send to didfinishinitialisation? confirm isMagConsistentAtInit is true
        }

        return isInitialised;
    }

    private boolean isMagConsistantAtInit = false;
    private Timer callbackTimer;


/*    public traceCallBack(int seconds){
        callBackTimer = new Timer();
        callBackTimer.schedule(new callUpdate(), seconds*1000);
    }*/

    class callUpdate extends TimerTask{

        @Override
        public void run() {
            //traceCWrapper.getLatestTraceResult();


        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_trace_manager);
    }

}

我没有足够的空间来添加 TraceCWrapper 文件,但是库加载为:

    static CLibrary lib = Native.loadLibrary("com.waymap.app.traceandroid", CLibrary.class);

作为主要示例,方法 traceCWrapper.provideDeviceMotion() 在 TraceCWrapper 中接收为:

    //Provide Device Motion
    public static boolean provideDeviceMotion(TCIMUEvent mTCIMUEvent, int Status, double userHeadingDeg, float rotationMode){

        DeviceMotion dM = new DeviceMotion();
        dM.setTcimuEvent(mTCIMUEvent);
        dM.setStatus(Status);
        dM.setUserHeadingDeg(userHeadingDeg);
        dM.setRotationMode(rotationMode);
        if(isRunning) {

            new sendToTraceHandleImuEvent().execute(dM);
            isInitalized = true;
            return isInitalized;
        }else{
            Log.i(TAG, "IMU update ignored as not running");
            isInitalized = false;
            return isInitalized;
        }
    }
    public static class sendToTraceHandleImuEvent extends AsyncTask<DeviceMotion,Void,Void>{

        @Override
        protected Void doInBackground(DeviceMotion... devicemotions) {
            /*public class Arg extends Structure {
                public devicemotions[] var1 = new byte[9];
                public devicemotions[] var2 = new byte[5];
            }*/
            Log.d(TAG, "InTraceCwrapper Again, provideIMU");

            lib.TraceHandleImuEvent(devicemotions[0].getTcimuEvent(), devicemotions[0].getStatus(), devicemotions[0].getUserHeadingDeg(), devicemotions[0].getRotationMode());
            return null;
        }

    }

您将不得不原谅大量的日志记录和多余的代码,因为我已经为此苦苦挣扎了一段时间。

传递我的 TCIMUEvent 时,我正在使用如下结构注释:

@Structure.FieldOrder({ "time", "accel", "accelValid", "mag", "magValid", "gyro", "gyroValid", "pressure", "pressureValid", "temperature", "temperatureValid"})
public class TCIMUEvent extends Structure implements Serializable {

    public double time;
    public float[] accel = new float[3];
    public boolean accelValid;
    public float[] mag = new float[3];
    public boolean magValid;
    public float[] gyro = new float[3];
    public boolean gyroValid;
    public float pressure;
    public boolean pressureValid;
    public float temperature;
    public boolean temperatureValid;

    public TCIMUEvent(double time, float[] accel, boolean accelValid, float[] mag, boolean magValid, float[] gyro, boolean gyroValid, float pressure, boolean pressureValid, float temperature, boolean temperatureValid) {
        this.time = time;
        this.accel = accel;
        this.accelValid = accelValid;
        this.mag = mag;
        this.magValid = magValid;
        this.gyro = gyro;
        this.gyroValid = gyroValid;
        this.pressure = pressure;
        this.pressureValid = pressureValid;
        this.temperature = temperature;
        this.temperatureValid = temperatureValid;
    }
}

需要的 Java C 映射:

    My Java Library to map:

    void TracehandleLocationEvent(TCLocationEvent tcLocationEvent);

    void TracehandleManualLocationEvent(TCManualLocationEvent tcManualLocationEvent);

    void TracehandleManualHeadingEvent(TCManualHeadingEvent tcManualHeadingEvent);

    void TracehandleManualInitialLocation(TCLocationEvent initialLocationEvent);

    void TraceHandleImuEvent(TCIMUEvent tcimuEvent, int Status, double userHeadingDeg, float rotationMode);

    void TraceGetResult(Double uptime, Pointer traceResult_out);

    -------- These map retrospectively to C:---------

    void TraceHandleLocationEvent (const Trace_locationSample_t *locationSample)

    void TraceHandleManualLocationEvent(const Trace_manualLocationSample_t
  *manualLocationSample)

    void TraceHandleManualHeadingEvent(const Trace_manualHeadingSample_t
  *manualHeadingSample)

     void TraceHandleLocationEvent (const Trace_locationSample_t *locationSample)

     void TraceHandleImuEvent(Trace_imuDataSample_t *imuDataSample, int *status,
  double *userHeadingDeg, StrapdownStreaming_RotationMode *currentRotateMode)

  void TraceGetResult(double time, Trace_Result_t *TraceResult)

新的Mappings是这样的,对象的结构和原题中的格式一样:


    void TracehandleLocationEvent(TCLocationEvent tcLocationEvent);

    void TracehandleManualLocationEvent(TCManualLocationEvent tcManualLocationEvent);

    void TracehandleManualHeadingEvent(TCManualHeadingEvent tcManualHeadingEvent);

    void TracehandleManualInitialLocation(TCLocationEvent initialLocationEvent);

    void TraceGetResult(DoubleByReference uptime, TCResult traceResult_out);

    void TraceHandleImuEvent(TCIMUEvent tcimuEvent, IntByReference status, DoubleByReference heading, FloatByReference rotationMode);

现在抛出的错误与我的 Structure 对象中的空构造函数有关:

java.lang.Error: Structure.getFieldOrder() on class com.dataTypes.TCLocationEvent returns names ([altitude, coordinate, horizontalAccuracy, timestamp, verticalAccuracy]) which do not match declared field names ([])
        at com.sun.jna.Structure.getFields(Structure.java:1089)
        at com.sun.jna.Structure.deriveLayout(Structure.java:1232)
        at com.sun.jna.Structure.calculateSize(Structure.java:1159)
        at com.sun.jna.Structure.calculateSize(Structure.java:1111)
        at com.sun.jna.Structure.allocateMemory(Structure.java:414)
        at com.sun.jna.Structure.<init>(Structure.java:205)
        at com.sun.jna.Structure.<init>(Structure.java:193)
        at com.sun.jna.Structure.<init>(Structure.java:180)
        at com.sun.jna.Structure.<init>(Structure.java:172)
        at com.dataTypes.TCLocationEvent.<init>(TCLocationEvent.java:30)
        at com.locationGetter.LocationService.<clinit>(LocationService.java:39)

JNA 映射的 SIGSEGV 错误通常是由访问不属于您的本机内存引起的。问题各不相同,但首先要看的是结构类型映射和 method/function 参数映射。

作为一个具体示例(可能还有更多),您的代码包含此映射:

void TraceHandleImuEvent(TCIMUEvent tcimuEvent, int Status,
    double userHeadingDeg, float rotationMode);

但是,本机映射不希望此处出现 intdoublefloat。它需要指针:

void TraceHandleImuEvent(Trace_imuDataSample_t *imuDataSample, int *status,
    double *userHeadingDeg, StrapdownStreaming_RotationMode *currentRotateMode)

(像 TCIMUEvent 这样的结构在作为参数传递时会自动映射到它们的指针,所以没关系。)

正在发生的事情是您正在传递 int 状态(例如 8),但本机代码正在考虑 "There's an integer stored at memory location 0x8." 您不拥有该内存,因此出现错误。

IntByReference 是正确的类型映射,对于许多函数参数也是如此。