summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Boehm <hboehm@google.com>2015-07-24 03:41:16 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2015-07-24 03:41:16 +0000
commit52572f4ee759502d3351b5d90c993844ef2b32d6 (patch)
tree7f7537a8a14b7e5a6bb6f910234d2dd5e6e0a8c1
parentfc231ad6d0b12e5f37cd17056582a462adcca0ea (diff)
parent2a3b06bd233e082af77d5eaa2009d30eac0beb60 (diff)
downloadandroid_packages_apps_ExactCalculator-52572f4ee759502d3351b5d90c993844ef2b32d6.tar.gz
android_packages_apps_ExactCalculator-52572f4ee759502d3351b5d90c993844ef2b32d6.tar.bz2
android_packages_apps_ExactCalculator-52572f4ee759502d3351b5d90c993844ef2b32d6.zip
am 2a3b06bd: am 51f5acc6: am 82e5a2f6: Avoid starting long uninterruptible computations
* commit '2a3b06bd233e082af77d5eaa2009d30eac0beb60': Avoid starting long uninterruptible computations
-rw-r--r--src/com/android/calculator2/BoundedRational.java11
-rw-r--r--src/com/android/calculator2/Evaluator.java49
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.