diff options
author | Hans Boehm <hboehm@google.com> | 2015-07-24 03:02:42 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-07-24 03:02:42 +0000 |
commit | 2a3b06bd233e082af77d5eaa2009d30eac0beb60 (patch) | |
tree | 6ebbe3e4cca28409254172988d7fa180b08ee90d | |
parent | 70f49ecd24447f735e78143358abd716482f783e (diff) | |
parent | 51f5acc6069b0ed9b4ee15132cc09e15b0307161 (diff) | |
download | android_packages_apps_ExactCalculator-2a3b06bd233e082af77d5eaa2009d30eac0beb60.tar.gz android_packages_apps_ExactCalculator-2a3b06bd233e082af77d5eaa2009d30eac0beb60.tar.bz2 android_packages_apps_ExactCalculator-2a3b06bd233e082af77d5eaa2009d30eac0beb60.zip |
am 51f5acc6: am 82e5a2f6: Avoid starting long uninterruptible computations
* commit '51f5acc6069b0ed9b4ee15132cc09e15b0307161':
Avoid starting long uninterruptible computations
-rw-r--r-- | src/com/android/calculator2/BoundedRational.java | 11 | ||||
-rw-r--r-- | src/com/android/calculator2/Evaluator.java | 49 |
2 files changed, 46 insertions, 14 deletions
diff --git a/src/com/android/calculator2/BoundedRational.java b/src/com/android/calculator2/BoundedRational.java index 70c21af..2b3d1ed 100644 --- a/src/com/android/calculator2/BoundedRational.java +++ b/src/com/android/calculator2/BoundedRational.java @@ -87,6 +87,11 @@ public class BoundedRational { return CR.valueOf(mNum).divide(CR.valueOf(mDen)); } + // Approximate number of bits to left of binary point. + public int wholeNumberBits() { + return mNum.bitLength() - mDen.bitLength(); + } + private boolean tooBig() { if (mDen.equals(BigInteger.ONE)) return false; return (mNum.bitLength() + mDen.bitLength() > MAX_SIZE); @@ -418,6 +423,9 @@ public class BoundedRational { // This algorithm is very naive, but we doubt it matters. long count = 0; while (n.mod(BigInteger.TEN).equals(BigInteger.ZERO)) { + if (Thread.interrupted()) { + throw new CR.AbortedException(); + } n = n.divide(BigInteger.TEN); ++count; } @@ -502,6 +510,9 @@ public class BoundedRational { if (r.mDen.equals(BigInteger.ONE)) return 0; r = r.reduce(); BigInteger den = r.mDen; + if (den.bitLength() > MAX_SIZE) { + return Integer.MAX_VALUE; + } while (!den.testBit(0)) { ++powers_of_two; den = den.shiftRight(1); diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java index a97d946..b779a68 100644 --- a/src/com/android/calculator2/Evaluator.java +++ b/src/com/android/calculator2/Evaluator.java @@ -302,7 +302,7 @@ class Evaluator { .show(); } - private final long MAX_TIMEOUT = 60000; + private final long MAX_TIMEOUT = 15000; // Milliseconds. // Longer is unlikely to help unless // we get more heap space. @@ -314,11 +314,12 @@ class Evaluator { // calculator is restarted. // We'll call that a feature; others // might argue it's a bug. - private final long mQuickTimeout = 1500; + private final long QUICK_TIMEOUT = 1000; // Timeout for unrequested, speculative // evaluations, in milliseconds. - // Could be shorter with a faster asin() - // implementation. + private int mMaxResultBits = 120000; // Don't try to display a larger result. + private final int MAX_MAX_RESULT_BITS = 350000; // Long timeout version. + private final int QUICK_MAX_RESULT_BITS = 50000; // Instant result version. private void displayTimeoutMessage() { final AlertDialog.Builder builder = new AlertDialog.Builder(mCalculator) @@ -329,6 +330,7 @@ class Evaluator { new DialogInterface.OnClickListener() { public void onClick(DialogInterface d, int which) { mTimeout = MAX_TIMEOUT; + mMaxResultBits = MAX_MAX_RESULT_BITS; } }); } @@ -368,21 +370,31 @@ class Evaluator { } @Override protected void onPreExecute() { - long timeout = mRequired ? mTimeout : mQuickTimeout; - if (timeout != 0) { - mTimeoutRunnable = new Runnable() { - @Override - public void run() { - handleTimeOut(); - } - }; - mTimeoutHandler.postDelayed(mTimeoutRunnable, timeout); + long timeout = mRequired ? mTimeout : QUICK_TIMEOUT; + mTimeoutRunnable = new Runnable() { + @Override + public void run() { + handleTimeOut(); + } + }; + mTimeoutHandler.postDelayed(mTimeoutRunnable, timeout); + } + private boolean isTooBig(CalculatorExpr.EvalResult res) { + int maxBits = mRequired ? mMaxResultBits : QUICK_MAX_RESULT_BITS; + if (res.mRatVal != null) { + return res.mRatVal.wholeNumberBits() > maxBits; + } else { + return res.mVal.get_appr(maxBits).bitLength() > 2; } } @Override protected InitialResult doInBackground(Void... nothing) { try { CalculatorExpr.EvalResult res = mExpr.eval(mDm); + if (isTooBig(res)) { + // Avoid starting a long uninterruptible decimal conversion. + return new InitialResult(R.string.timeout); + } int prec = INIT_PREC; String initCache = res.mVal.toString(prec); int msd = getMsdPos(initCache); @@ -422,7 +434,14 @@ class Evaluator { mEvaluator = null; mTimeoutHandler.removeCallbacks(mTimeoutRunnable); if (result.isError()) { - mCalculator.onError(result.mErrorResourceId); + if (result.mErrorResourceId == R.string.timeout) { + if (mRequired) { + displayTimeoutMessage(); + } + mCalculator.onCancelled(); + } else { + mCalculator.onError(result.mErrorResourceId); + } return; } mVal = result.mVal; @@ -453,6 +472,8 @@ class Evaluator { } @Override protected void onCancelled(InitialResult result) { + // Invoker resets mEvaluator. + mTimeoutHandler.removeCallbacks(mTimeoutRunnable); if (mRequired && !mQuiet) { displayCancelledMessage(); } // Otherwise timeout processing displayed message. |