maplibre-native icon indicating copy to clipboard operation
maplibre-native copied to clipboard

SIGABRT (Pure virtual function called) on maplibre android v11.5.0 (latest version)

Open jcrabanal opened this issue 1 year ago • 1 comments

Describe the bug An exception in native code happens that crash the app.

To Reproduce Sorry, I am not sure how to reproduce this. It happens after 10-15 seconds while using the map. Sometimes it happens after a click or a zoom change.

Expected behavior No crash should happen.

Platform information (please complete the following information): Android 15 (not relevant, happens on a variety of versions)

I've attached a stack trace. Let me know if you need anything else. log_maplibre.txt

jcrabanal avatar Oct 01 '24 10:10 jcrabanal

I've tracked down the bug to the following function in my code. The crash always happen when calling copyLayer.setProperties(textSize1)

private void addHighlightedLayer(@NonNull List<Layer> lstLayers,
                                 @NonNull List<Feature> lstFeatures,
                                 int nRepeatCount,
                                 int nLineWidth,
                                 @Nullable Float nOpacity,
                                 @Nullable Float nMinZoom,
                                 @Nullable Float nMaxZoom) {
    Style style = getStyle();
    if (style == null) {
        throw new IllegalStateException("Style not loaded yet");
    }
    int nCount = lstLayers.size();
    for (String sIdLayer : lstHighlightedLayerIds) {
        style.removeLayer(sIdLayer);
    }
    for (String sIdSource : lstHighlightedSourceIds) {
        style.removeSource(sIdSource);
    }
    lstHighlightedLayerIds.clear();
    lstHighlightedSourceIds.clear();
    for (int i = 0; i < nCount; i++) {
        Layer layer = lstLayers.get(i);
        Feature feature = lstFeatures.get(i);
        FeatureCollection featureCollection = FeatureCollection.fromFeature(feature);
        String sSourceId = Utils.getRandomAlphabeticString(16);
        style.addSource(new GeoJsonSource(sSourceId, featureCollection));
        lstHighlightedSourceIds.add(sSourceId);
        if (layer instanceof SymbolLayer) {
            SymbolLayer symbolLayer = (SymbolLayer) layer;
            String sLayerId = Utils.getRandomAlphabeticString(16);
            lstHighlightedLayerIds.add(sLayerId);
            SymbolLayer copyLayer = new SymbolLayer(sLayerId, sSourceId);
            Expression filter = symbolLayer.getFilter();
            if (filter != null) {
                copyLayer.setFilter(filter);
            }
            PropertyValue<Float> textSize = symbolLayer.getTextSize();
            float nFinalOpacity = nOpacity == null ? 1f : nOpacity;
            PropertyValue<Float> opacity = PropertyFactory.iconOpacity(nFinalOpacity);
            copyLayer.setProperties(symbolLayer.getTextFont(),
                    symbolLayer.getTextField(),
                    symbolLayer.getTextAllowOverlap(),
                    symbolLayer.getVisibility(),
                    symbolLayer.getTextColor(),
                    symbolLayer.getTextHaloWidth(),
                    symbolLayer.getTextHaloColor(),
                    opacity);
            float nFinalMinZoom = nMinZoom == null ? symbolLayer.getMinZoom() : nMinZoom;
            float nFinalMaxZoom = nMaxZoom == null ? symbolLayer.getMaxZoom() : nMaxZoom;
            copyLayer.setMinZoom(nFinalMinZoom);
            copyLayer.setMaxZoom(nFinalMaxZoom);
            selectedLayerAnimator = new ValueAnimator();
            selectedLayerAnimator.setObjectValues(textSize.value, textSize.value + 50);
            selectedLayerAnimator.setDuration(2000);
            // Impar para volver a origen
            selectedLayerAnimator.setRepeatCount(nRepeatCount);
            selectedLayerAnimator.setRepeatMode(ValueAnimator.REVERSE);
            selectedLayerAnimator.addUpdateListener(animator -> {
                try {
                    PropertyValue<Float> textSize1 = PropertyFactory.textSize((float) animator.getAnimatedValue());
                    copyLayer.setProperties(textSize1);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
            selectedLayerAnimator.start();
            style.addLayerAbove(copyLayer, symbolLayer.getId());
        } else if (layer instanceof LineLayer) {
            LineLayer lineLayer = (LineLayer) layer;
            String sLayerId = Utils.getRandomAlphabeticString(16);
            lstHighlightedLayerIds.add(sLayerId);
            LineLayer copyLayer = new LineLayer(sLayerId, sSourceId);
            Expression filter = lineLayer.getFilter();
            if (filter != null) {
                copyLayer.setFilter(filter);
            }
            PropertyValue<Float> lineWidth = lineLayer.getLineWidth();
            float nFinalOpacity = nOpacity == null ? 1f : nOpacity;
            PropertyValue<Float> opacity = PropertyFactory.lineOpacity(nFinalOpacity);
            lineWidth = new PropertyValue<>(lineWidth.name, lineWidth.value);
            copyLayer.setProperties(lineWidth,
                    lineLayer.getVisibility(),
                    lineLayer.getLineColor(),
                    lineLayer.getLineWidth(),
                    opacity);
            float nFinalMinZoom = nMinZoom == null ? lineLayer.getMinZoom() : nMinZoom;
            float nFinalMaxZoom = nMaxZoom == null ? lineLayer.getMaxZoom() : nMaxZoom;
            copyLayer.setMinZoom(nFinalMinZoom);
            copyLayer.setMaxZoom(nFinalMaxZoom);
            selectedLayerAnimator = new ValueAnimator();
            selectedLayerAnimator.setObjectValues(lineWidth.value, lineWidth.value + nLineWidth);
            selectedLayerAnimator.setDuration(2000);
            // Impar para volver a origen
            selectedLayerAnimator.setRepeatCount(nRepeatCount);
            selectedLayerAnimator.setRepeatMode(ValueAnimator.REVERSE);
            selectedLayerAnimator.addUpdateListener(animator -> {
                try {
                    PropertyValue<Float> textSize1 = PropertyFactory.lineWidth((float) animator.getAnimatedValue());
                    copyLayer.setProperties(textSize1);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            });
            selectedLayerAnimator.start();
            style.addLayerAbove(copyLayer, lineLayer.getId());
        }
    }
}

I use a ValueAnimator to grow/shrink a selected feature. I only cancel() the ValueAnimator when another feature is selected. My guess is that at some point the layer is invalid and the memory gets corrupted.

Is there any other (built-in or not) way I could achieve this effect?

jcrabanal avatar Oct 01 '24 15:10 jcrabanal

We're getting crashes on v11.5.1 that might be related to this error tombstone_00.txt tombstone_01.txt

alasram avatar Oct 25 '24 23:10 alasram