OSDN Git Service

targetSdkVersion float property sanitization
authorJohn Reck <jreck@google.com>
Wed, 6 Dec 2017 17:46:13 +0000 (09:46 -0800)
committerandroid-build-team Robot <android-build-team-robot@google.com>
Thu, 7 Dec 2017 00:55:29 +0000 (00:55 +0000)
Bug: 70242902
Test: CTS tests checking for exception still pass
Change-Id: I77dd772a6cb7077de058a3ca85b984c2c3f7321e
(cherry picked from commit c888788cb969a5cd3a17ab396a2e02555d2717f5)

core/java/android/view/View.java

index 0525ab1..1e75fc9 100644 (file)
@@ -893,6 +893,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      */
     private static boolean sAutoFocusableOffUIThreadWontNotifyParents;
 
+    /**
+     * Prior to P things like setScaleX() allowed passing float values that were bogus such as
+     * Float.NaN. If the app is targetting P or later then passing these values will result in an
+     * exception being thrown. If the app is targetting an earlier SDK version, then we will
+     * silently clamp these values to avoid crashes elsewhere when the rendering code hits
+     * these bogus values.
+     */
+    private static boolean sThrowOnInvalidFloatProperties;
+
     /** @hide */
     @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO})
     @Retention(RetentionPolicy.SOURCE)
@@ -4752,6 +4761,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
             sUseDefaultFocusHighlight = context.getResources().getBoolean(
                     com.android.internal.R.bool.config_useDefaultFocusHighlight);
 
+            sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P;
+
             sCompatibilityDone = true;
         }
     }
@@ -14275,7 +14286,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      */
     public void setScaleX(float scaleX) {
         if (scaleX != getScaleX()) {
-            requireIsFinite(scaleX, "scaleX");
+            scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX");
             invalidateViewProperty(true, false);
             mRenderNode.setScaleX(scaleX);
             invalidateViewProperty(false, true);
@@ -14312,7 +14323,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      */
     public void setScaleY(float scaleY) {
         if (scaleY != getScaleY()) {
-            requireIsFinite(scaleY, "scaleY");
+            scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY");
             invalidateViewProperty(true, false);
             mRenderNode.setScaleY(scaleY);
             invalidateViewProperty(false, true);
@@ -14862,13 +14873,41 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
         }
     }
 
-    private static void requireIsFinite(float transform, String propertyName) {
-        if (Float.isNaN(transform)) {
-            throw new IllegalArgumentException("Cannot set '" + propertyName + "' to Float.NaN");
+    private static float sanitizeFloatPropertyValue(float value, String propertyName) {
+        return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE);
+    }
+
+    private static float sanitizeFloatPropertyValue(float value, String propertyName,
+            float min, float max) {
+        // The expected "nothing bad happened" path
+        if (value >= min && value <= max) return value;
+
+        if (value < min || value == Float.NEGATIVE_INFINITY) {
+            if (sThrowOnInvalidFloatProperties) {
+                throw new IllegalArgumentException("Cannot set '" + propertyName + "' to "
+                        + value + ", the value must be >= " + min);
+            }
+            return min;
         }
-        if (Float.isInfinite(transform)) {
-            throw new IllegalArgumentException("Cannot set '" + propertyName + "' to infinity");
+
+        if (value > max || value == Float.POSITIVE_INFINITY) {
+            if (sThrowOnInvalidFloatProperties) {
+                throw new IllegalArgumentException("Cannot set '" + propertyName + "' to "
+                        + value + ", the value must be <= " + max);
+            }
+            return max;
         }
+
+        if (Float.isNaN(value)) {
+            if (sThrowOnInvalidFloatProperties) {
+                throw new IllegalArgumentException(
+                        "Cannot set '" + propertyName + "' to Float.NaN");
+            }
+            return 0; // Unclear which direction this NaN went so... 0?
+        }
+
+        // Shouldn't be possible to reach this.
+        throw new IllegalStateException("How do you get here?? " + value);
     }
 
     /**
@@ -14957,7 +14996,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      */
     public void setElevation(float elevation) {
         if (elevation != getElevation()) {
-            requireIsFinite(elevation, "elevation");
+            elevation = sanitizeFloatPropertyValue(elevation, "elevation");
             invalidateViewProperty(true, false);
             mRenderNode.setElevation(elevation);
             invalidateViewProperty(false, true);
@@ -15050,7 +15089,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
      */
     public void setTranslationZ(float translationZ) {
         if (translationZ != getTranslationZ()) {
-            requireIsFinite(translationZ, "translationZ");
+            translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ");
             invalidateViewProperty(true, false);
             mRenderNode.setTranslationZ(translationZ);
             invalidateViewProperty(false, true);