Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] App crash in release build works fine in debug build #1778

Open
bluntbrain opened this issue Aug 9, 2023 · 2 comments
Open

[Android] App crash in release build works fine in debug build #1778

bluntbrain opened this issue Aug 9, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@bluntbrain
Copy link

bluntbrain commented Aug 9, 2023

Description

Logs
---------------------------- PROCESS STARTED (27444) for package com.couplapp ----------------------------
2023-08-09 19:58:54.086 27442-27442 DEBUG crash_dump64 A Cmdline: com.couplapp
2023-08-09 19:58:54.087 27442-27442 DEBUG crash_dump64 A pid: 26928, tid: 26928, name: com.couplapp >>> com.couplapp <<<
2023-08-09 19:58:54.087 27442-27442 DEBUG crash_dump64 A #00 pc 0000000000065694 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/lib/arm64/libreanimated.so (BuildId: 4e2ea9c5275a9c49b5fdd425d29436cffd96a7b0)
2023-08-09 19:58:54.087 27442-27442 DEBUG crash_dump64 A #1 pc 0000000000080a78 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/lib/arm64/libreanimated.so (reanimated::Scheduler::triggerUI()+240) (BuildId: 4e2ea9c5275a9c49b5fdd425d29436cffd96a7b0)
2023-08-09 19:58:54.087 27442-27442 DEBUG crash_dump64 A #2 pc 0000000000084098 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/lib/arm64/libreanimated.so (facebook::jni::detail::MethodWrapper<void (reanimated::AndroidScheduler::)(), &(reanimated::AndroidScheduler::triggerUI()), reanimated::AndroidScheduler, void>::dispatch(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject>)+44) (BuildId: 4e2ea9c5275a9c49b5fdd425d29436cffd96a7b0)
2023-08-09 19:58:54.087 27442-27442 DEBUG crash_dump64 A #3 pc 0000000000084004 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/lib/arm64/libreanimated.so (facebook::jni::detail::FunctionWrapper<void ()(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject>), facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject*, void>::call(_JNIEnv*, _jobject*, void ()(facebook::jni::alias_ref<facebook::jni::detail::JTypeFor<facebook::jni::HybridClass<reanimated::AndroidScheduler, facebook::jni::detail::BaseHybridClass>::JavaPart, facebook::jni::JObject, void>::_javaobject>))+60) (BuildId: 4e2ea9c5275a9c49b5fdd425d29436cffd96a7b0)
2023-08-09 19:58:54.087 27442-27442 DEBUG crash_dump64 A #4 pc 0000000000082e88 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/lib/arm64/libreanimated.so (facebook::jni::detail::MethodWrapper<void (reanimated::AndroidScheduler::)(), &(reanimated::AndroidScheduler::triggerUI()), reanimated::AndroidScheduler, void>::call(_JNIEnv, _jobject*)+36) (BuildId: 4e2ea9c5275a9c49b5fdd425d29436cffd96a7b0)
2023-08-09 19:58:54.088 27442-27442 DEBUG crash_dump64 A #5 pc 0000000000073a54 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/oat/arm64/base.odex (art_jni_trampoline+116)
2023-08-09 19:58:54.088 27442-27442 DEBUG crash_dump64 A #7 pc 0000000000347626 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/oat/arm64/base.vdex (com.swmansion.reanimated.Scheduler$1.run+28)
2023-08-09 19:58:54.088 27442-27442 DEBUG crash_dump64 A #9 pc 000000000034764e /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/oat/arm64/base.vdex (com.swmansion.reanimated.Scheduler$2.runGuarded+12)
2023-08-09 19:58:54.088 27442-27442 DEBUG crash_dump64 A #10 pc 00000000000a9e94 /data/app/~~z7gaWc39l7ruURuChwu_Jw==/com.couplapp-Dq-SH5U1RGI0vq66qWdGeQ==/oat/arm64/base.odex (com.facebook.react.bridge.GuardedRunnable.run+52)
2023-08-09 19:58:54.171 4887-4887 audit auditd E type=1701 audit(1691591334.167:65904): auid=4294967295 uid=10448 gid=10448 ses=4294967295 subj=u:r:untrusted_app_30:s0:c192,c257,c512,c768 pid=26928 comm="com.couplapp" exe="/system/bin/app_process64" sig=11 res=1
2023-08-09 19:58:54.452 5403-5445 WindowManager system_server E win=Window{1bf733c u0 com.couplapp/com.couplapp.MainActivity EXITING} destroySurfaces: appStopped=false cleanupOnResume=false win.mWindowRemovalAllowed=true win.mRemoveOnExit=true win.mViewVisibility=0 caller=com.android.server.wm.ActivityRecord.destroySurfaces:6529 com.android.server.wm.ActivityRecord.destroySurfaces:6510 com.android.server.wm.WindowState.onExitAnimationDone:5965 com.android.server.wm.ActivityRecord$$ExternalSyntheticLambda10.accept:2 java.util.ArrayList.forEach:1262 com.android.server.wm.ActivityRecord.onAnimationFinished:8569 com.android.server.wm.ActivityRecord.postApplyAnimation:6243
---------------------------- PROCESS ENDED (26928) for package com.couplapp ----------------------------

Version

0.1.195

Steps to reproduce

"react": "18.1.0",
"react-native": "0.70.6",
"@shopify/react-native-skia": "^0.1.195",

Snack, code example, screenshot, or link to a repository

import {
  StyleSheet,
  Text,
  View,
  Dimensions,
  TouchableOpacity,
} from 'react-native';
import React from 'react';
import {curveBasis, line, scaleLinear, select} from 'd3';
import {
  Canvas,
  Circle,
  Group,
  LinearGradient,
  Path,
  Skia,
  useTouchHandler,
  useValue,
  vec,
  useComputedValue,
  PathVerb,
  Line,
} from '@shopify/react-native-skia';
import arrow from '../assets/images/greyArrowRight.png';
import {Image} from 'react-native';
import {getAdjacentMonth} from '../utils/lineGraphHelpers';
import {formatCurrency, log} from '../utils/helperFunctions';

const width = Dimensions.get('window').width * 1.08;
const height = 200;

const useGraphTouchHandler = (x, setValue) => {
  return useTouchHandler({
    onActive: e => {
      const lowerBound = width / 8 + 10;
      const upperBound = (width / 8) * 7;
      if (e.x > lowerBound && e.x < upperBound) {
        x.current = e.x;
        setValue(e.x);
      }
    },
  });
};

const Cursor = ({x, y}) => {
  const transform = useComputedValue(
    () => [{translateX: x.current}, {translateY: y.current}],
    [x, y],
  );
  return (
    <Group transform={transform}>
      <Circle cx={0} cy={0} r={8} color={'#244566'} />
      <Circle cx={0} cy={0} r={16} color={'#244566'} opacity={0.15} />
      <Line
        p1={vec(0, 0)}
        p2={vec(0, height)}
        color={'#244566'}
        strokeWidth={1}
      />
    </Group>
  );
};
const selectCurve = (cmds, x) => {
  let from = vec(0, 0);
  for (let i = 0; i < cmds.length; i++) {
    const cmd = cmds[i];
    if (cmd[0] === PathVerb.Move) {
      from = vec(cmd[1], cmd[2]);
    } else if (cmd[0] === PathVerb.Cubic) {
      const c1 = vec(cmd[1], cmd[2]);
      const c2 = vec(cmd[3], cmd[4]);
      const to = vec(cmd[5], cmd[6]);
      if (x >= from.x && x <= to.x) {
        return {
          from,
          c1,
          c2,
          to,
        };
      }
      from = to;
    }
  }
  return null;
};
const cubicBezier = (t, from, c1, c2, to) => {
  const term = 1 - t;
  const a = 1 * term ** 3 * t ** 0 * from;
  const b = 3 * term ** 2 * t ** 1 * c1;
  const c = 3 * term ** 1 * t ** 2 * c2;
  const d = 1 * term ** 0 * t ** 3 * to;
  return a + b + c + d;
};
const round = (value, precision = 0) => {
  const p = Math.pow(10, precision);
  return Math.round(value * p) / p;
};
const cuberoot = x => {
  'worklet';
  const y = Math.pow(Math.abs(x), 1 / 3);
  return x < 0 ? -y : y;
};
const cubicBezierYForX = (x, a, b, c, d, precision = 2) => {
  const pa = -a.x + 3 * b.x - 3 * c.x + d.x;
  const pb = 3 * a.x - 6 * b.x + 3 * c.x;
  const pc = -3 * a.x + 3 * b.x;
  const pd = a.x - x;
  const t = solveCubic(pa, pb, pc, pd)
    .map(root => round(root, precision))
    .filter(root => root >= 0 && root <= 1)[0];

  return cubicBezier(t, a.y, b.y, c.y, d.y);
};
const solveCubic = (a, b, c, d) => {
  if (Math.abs(a) < 1e-8) {
    // Quadratic case, ax^2+bx+c=0
    a = b;
    b = c;
    c = d;
    if (Math.abs(a) < 1e-8) {
      // Linear case, ax+b=0
      a = b;
      b = c;
      if (Math.abs(a) < 1e-8) {
        // Degenerate case
        return [];
      }
      return [-b / a];
    }

    const D = b * b - 4 * a * c;
    if (Math.abs(D) < 1e-8) {
      return [-b / (2 * a)];
    } else if (D > 0) {
      return [(-b + Math.sqrt(D)) / (2 * a), (-b - Math.sqrt(D)) / (2 * a)];
    }
    return [];
  }

  // Convert to depressed cubic t^3+pt+q = 0 (subst x = t - b/3a)
  const p = (3 * a * c - b * b) / (3 * a * a);
  const q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
  let roots;

  if (Math.abs(p) < 1e-8) {
    // p = 0 -> t^3 = -q -> t = -q^1/3
    roots = [cuberoot(-q)];
  } else if (Math.abs(q) < 1e-8) {
    // q = 0 -> t^3 + pt = 0 -> t(t^2+p)=0
    roots = [0].concat(p < 0 ? [Math.sqrt(-p), -Math.sqrt(-p)] : []);
  } else {
    const D = (q * q) / 4 + (p * p * p) / 27;
    if (Math.abs(D) < 1e-8) {
      // D = 0 -> two roots
      roots = [(-1.5 * q) / p, (3 * q) / p];
    } else if (D > 0) {
      // Only one real root
      const u = cuberoot(-q / 2 - Math.sqrt(D));
      roots = [u - p / (3 * u)];
    } else {
      // D < 0, three roots, but needs to use complex numbers/trigonometric solution
      const u = 2 * Math.sqrt(-p / 3);
      const t = Math.acos((3 * q) / p / u) / 3; // D < 0 implies p < 0 and acos argument in [-1..1]
      const k = (2 * Math.PI) / 3;
      roots = [u * Math.cos(t), u * Math.cos(t - k), u * Math.cos(t - 2 * k)];
    }
  }

  // Convert back from depressed cubic
  for (let i = 0; i < roots.length; i++) {
    roots[i] -= b / (3 * a);
  }

  return roots;
};

const getYForX = (path, x, precision = 2) => {
  const cmds = path.toCmds();
  const c = selectCurve(cmds, x);
  if (c === null) {
    return 0;
  }
  return cubicBezierYForX(x, c.from, c.c1, c.c2, c.to, precision);
};

const months = {
  1: 'Jan',
  2: 'Feb',
  3: 'Mar',
  4: 'Apr',
  5: 'May',
  6: 'Jun',
  7: 'Jul',
  8: 'Aug',
  9: 'Sep',
  10: 'Oct',
  11: 'Nov',
  12: 'Dec',
};

const getGraphMonthValue = monthNo => {
  const month = monthNo % 100;
  const year = String(monthNo).split('').slice(0, 4).join('');

  return year * 100 + (month * 100) / 12;
};

export default function LineGraph({
  data = [],
  getPrevMonth = () => {},
  getNextMonth = () => {},
  isPrev = true,
  isNext = true,
}) {
  const makeGraph = () => {
    const edgedData = [
      {value: 0, monthNo: getAdjacentMonth(data[0].monthNo, 'prev')},
      ...data,
      {value: 0, monthNo: getAdjacentMonth(data[5].monthNo, 'next')},
    ].map(item => {
      log(item);
      return {
        ...item,
        monthNo: getGraphMonthValue(item.monthNo),
      };
    });

    log('path data', edgedData);
    const minY = Math.min(...edgedData.map(item => item.value));
    const maxY = Math.max(...edgedData.map(item => item.value));

    const getYaxis = scaleLinear()
      .domain([minY, maxY])
      .range([height - 2, 0]);

    const minX = Math.min(...edgedData?.map(item => item.monthNo));
    const maxX = Math.max(...edgedData?.map(item => item.monthNo));

    const getXaxis = scaleLinear().domain([minX, maxX]).range([0, width]);

    const curvedLine = line()
      .x(d => getXaxis(d.monthNo))
      .y(d => getYaxis(d.value))
      .curve(curveBasis)(edgedData);

    return {
      curve: curvedLine,
    };
  };

  const getGradientAreaSplit = (
    graphLine, // the line created above
    width,
    height, // in my use case this is the graph height / 2, i.e. area above or below y=0
    variant = 'positive',
  ) => {
    // 1) The initial graph line (which can go below or above y=0)
    const gradientAreaSplit =
      Skia.Path.MakeFromSVGString(graphLine ?? '0') ?? Skia.Path.Make();
    const useFirstY =
      (variant === 'positive' && gradientAreaSplit.getPoint(0).y > 0) ||
      (variant === 'negative' && gradientAreaSplit.getPoint(0).y < 0);
    gradientAreaSplit
      // 2) Extend line to y=0 at the right end
      .lineTo(width, height)
      // 3) Extend line to y=0 at the left end
      .lineTo(0, height)
      // 4) Extend line to first point to close the area if that point is in the area, otherwise to y=0 (see useFirstY logic)
      .lineTo(0, useFirstY ? gradientAreaSplit.getPoint(0).y : height);
    return gradientAreaSplit;
  };

  const graphPath = makeGraph();

  const skiaPath = Skia.Path.MakeFromSVGString(graphPath.curve);

  const graphGradientPath = getGradientAreaSplit(
    graphPath.curve,
    width,
    height + 40,
  );

  const [currentIndex, setCurrentIndex] = React.useState(0);
  const [xValue, setXvalue] = React.useState(0);
  const x = useValue(0);
  const y = useComputedValue(
    () => getYForX(skiaPath, x.current),
    [skiaPath, x],
  );

  const getSpentFromX = x => {
    const onePartWidth = width / 8;
    const howManyParts = x / onePartWidth;
    const arrIndex = Math.round(howManyParts - 1.5);
    // log('@@ arrindex: ', arrIndex);
    setCurrentIndex(Math.max(0, Math.min(5, arrIndex)));
  };

  const handleMonthTap = index => {
    console.log('month index: ', index);

    const onePartWidth = width / 8;
    const localX = Math.floor(onePartWidth * (index * 1.02 + 1.5));
    x.current = localX;
    setXvalue(localX);
  };

  React.useEffect(() => {
    getSpentFromX(xValue);
  }, [xValue]);

  const onTouch = useGraphTouchHandler(x, setXvalue);

  return (
    <>
      <View style={styles.headerContainer}>
        <Text style={styles.header}>Month-wise Spends</Text>
        <View
          style={{
            flexDirection: 'row',
            backgroundColor: '#E4F3FF',
            paddingHorizontal: 16,
            paddingVertical: 10,
            borderRadius: 4,
          }}>
          <Text style={styles.header}>
            {months[data[currentIndex].monthNo % 100]} '
            {String(data[currentIndex].monthNo).split('').slice(2, 4).join('')}
          </Text>
          <Text
            style={[
              styles.header,
              {marginLeft: 10, fontFamily: 'Inter-SemiBold'},
            ]}>
            ₹{formatCurrency(data[currentIndex].value)}
          </Text>
        </View>
      </View>
      <View
        style={{transform: [{translateX: -width * 0.04}], paddingBottom: 10}}>
        <Canvas style={{height: height, width}} onTouch={onTouch}>
          <Path
            path={graphGradientPath}
            color="#244566"
            strokeWidth={3}
            style="stroke"
          />
          <Path path={graphGradientPath}>
            <LinearGradient
              start={vec(0, height / 1.2)}
              end={vec(0, 0)}
              colors={['#fff', '#79C0FF85']}
            />
          </Path>
          <Cursor x={x} y={y} />
        </Canvas>
      </View>
      <View style={styles.xAxisContainer}>
        <TouchableOpacity
          style={[styles.arrowButton, {opacity: isPrev ? 1 : 0.2}]}
          disabled={!isPrev}
          onPress={getPrevMonth}>
          <Image
            source={arrow}
            style={[
              styles.arrowImage,
              {transform: [{rotate: '180deg'}, {translateY: -1}]},
            ]}
            resizeMode="contain"
          />
        </TouchableOpacity>
        {data?.map((item, i) => (
          <TouchableOpacity
            key={i}
            style={{padding: 10}}
            onPress={() => handleMonthTap(i)}>
            <Text
              style={[
                styles.monthName,
                {
                  color:
                    item?.monthNo === data[currentIndex].monthNo
                      ? '#204065'
                      : 'rgba(0, 0, 0, 0.60)',
                  fontFamily:
                    item?.monthNo === data[currentIndex].monthNo
                      ? 'Inter-SemiBold'
                      : 'Inter-Regular',
                },
              ]}>
              {months[parseInt(item?.monthNo % 100)]}
            </Text>
          </TouchableOpacity>
        ))}
        <TouchableOpacity
          style={[styles.arrowButton, {opacity: isNext ? 1 : 0.2}]}
          disabled={!isNext}
          onPress={getNextMonth}>
          <Image
            source={arrow}
            style={styles.arrowImage}
            resizeMode="contain"
          />
        </TouchableOpacity>
      </View>
    </>
  );
}
@bluntbrain bluntbrain added the bug Something isn't working label Aug 9, 2023
@bluntbrain
Copy link
Author

@wcandillon @chrfalch
Can you guys please check and help in this one, thanks in advance

@wcandillon
Copy link
Collaborator

Thank you for reporting this issue, we are really interested to fix it. Could you make the code snippet smaller? Also it is not runnable as a standalone piece of code as it has dependencies with external files. Anything you can do to help us reproduce the issue on our side would be extremely helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants