am cf612572: (-s ours) Merge "DO NOT MERGE: Revert "Revert "Fix for ByodFlowTestActivity""" into lollipop-mr1-cts-dev
* commit 'cf6125722712cdb11cf4f62482c06f66a2fc72e9':
DO NOT MERGE: Revert "Revert "Fix for ByodFlowTestActivity""
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 2ef9b62..6f475cc 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -182,6 +182,7 @@
CtsHostJank \
CtsHostsideNetworkTests \
CtsHostUi \
+ CtsJdwpSecurityHostTestCases \
CtsMonkeyTestCases \
CtsThemeHostTestCases \
CtsSecurityHostTestCases \
@@ -204,6 +205,7 @@
cts_device_jars := \
CtsDeviceJank \
+ CtsJdwpApp \
CtsPrintInstrument
cts_device_executables := \
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index a364e22..17ddbac 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -951,6 +951,17 @@
android:value="android.hardware.camera.any"/>
</activity>
+ <activity android:name=".camera.its.ItsTestActivity"
+ android:label="@string/camera_its_test"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_camera" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.camera.any" />
+ </activity>
+
<activity android:name=".usb.UsbAccessoryTestActivity"
android:label="@string/usb_accessory_test"
android:configChanges="keyboardHidden|orientation|screenSize">
@@ -1282,7 +1293,6 @@
</activity>
<activity android:name=".managedprovisioning.ByodHelperActivity">
- android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_QUERY" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_REMOVE" />
@@ -1424,8 +1434,6 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_other" />
- <meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
</activity>
<activity android:name=".tv.MockTvInputSettingsActivity">
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 07f7654..1444723 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1164,6 +1164,7 @@
<string name="provisioning_byod_no_video_capture_resolver">No video capture app present. Skip test.</string>
<string name="provisioning_byod_no_audio_capture_resolver">No audio capture app present. Skip test.</string>
<string name="provisioning_byod_capture_media_error">Error while capturing media from managed profile.</string>
+ <string name="provisioning_byod_capture_image_error">Error while capturing image from managed profile.</string>
<!-- Strings for DeskClock -->
<string name="deskclock_tests">Alarms and Timers Tests</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 90912ea..800137a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -196,12 +196,6 @@
}
@Override
- public void onConfigurationChanged(Configuration newConfig){
- Log.v(TAG,"onConfigurationChanged");
- super.onConfigurationChanged(newConfig);
- }
-
- @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_INSTALL_PACKAGE: {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
index b3f126b..15f5bc8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodPresentMediaDialog.java
@@ -31,10 +31,14 @@
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.VideoView;
-
+import android.view.Display;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.content.ContentResolver;
import com.android.cts.verifier.R;
import java.io.IOException;
+import java.io.InputStream;
/**
* This dialog shows/plays an image, video or audio uri.
@@ -46,6 +50,7 @@
private static final String KEY_IMAGE_URI = "image";
private static final String KEY_AUDIO_URI = "audio";
+ private Bitmap scaled = null;
/**
* Get a dialogFragment showing an image.
*/
@@ -79,6 +84,16 @@
return dialog;
}
+ private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
+ // Raw height and width of image
+ final int height = options.outHeight;
+ final int width = options.outWidth;
+ if(reqWidth <= 0 || reqHeight <= 0) {
+ return 1;
+ }
+ return Math.max(height/reqHeight, width/reqWidth) + 1;
+ }
+
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Dialog dialog = new Dialog(getActivity());
@@ -114,11 +129,36 @@
} else if (arguments.containsKey(KEY_IMAGE_URI)) {
// Show image UI.
dialog.setTitle(getString(R.string.provisioning_byod_verify_image_title));
-
- Uri uri = (Uri) getArguments().getParcelable(KEY_IMAGE_URI);
+ Uri uri = (Uri)getArguments().getParcelable(KEY_IMAGE_URI);
ImageView imageView = (ImageView) dialog.findViewById(R.id.imageView);
imageView.setVisibility(View.VISIBLE);
- imageView.setImageURI(uri);
+
+ try{
+ InputStream input = getActivity().getContentResolver().openInputStream(uri);
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeStream(input, null, options);
+ //scale the picture
+ Display display = getActivity().getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ int reqWidth = size.x;
+ int reqHeight = size.y;
+ options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
+
+ options.inJustDecodeBounds = false;
+ input.close();
+ input = getActivity().getContentResolver().openInputStream(uri);
+ scaled = BitmapFactory.decodeStream(input, null, options);
+ input.close();
+ imageView.setImageBitmap(scaled);
+ }catch(IOException e){
+ Log.e(TAG, "Cannot get image.", e);
+ Toast.makeText(getActivity(),R.string.provisioning_byod_capture_image_error,
+ Toast.LENGTH_SHORT).show();
+ getActivity().finish();
+ }
+
} else if (arguments.containsKey(KEY_AUDIO_URI)) {
// Show audio playback UI.
dialog.setTitle(getString(R.string.provisioning_byod_verify_audio_title));
@@ -161,6 +201,13 @@
((DialogCallback) getActivity()).onDialogClose();
}
+ @Override
+ public void onDestroyView() {
+ if(scaled!=null){
+ scaled.recycle();
+ }
+ super.onDestroyView();
+ }
public interface DialogCallback {
public abstract void onDialogClose();
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
index 7e49f80..32be962 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsSingleUserTest.java
@@ -24,10 +24,8 @@
* Set of tests for LauncherApps with managed profiles.
*/
public class LauncherAppsSingleUserTest extends BaseLauncherAppsTest {
- private static final String FEATURE_LIVE_TV = "android.software.live_tv";
private boolean mHasLauncherApps;
- private boolean mHasLiveTvFeature;
@Override
protected void setUp() throws Exception {
@@ -37,8 +35,6 @@
if (mHasLauncherApps) {
installTestApps();
}
-
- mHasLiveTvFeature = hasDeviceFeature(FEATURE_LIVE_TV);
}
@Override
@@ -100,7 +96,7 @@
}
public void testLauncherCallbackPackageChangedMainUser() throws Exception {
- if (!mHasLauncherApps || mHasLiveTvFeature) {
+ if (!mHasLauncherApps) {
return;
}
installApp(SIMPLE_APP_APK);
@@ -118,7 +114,7 @@
}
public void testLauncherNonExportedAppFails() throws Exception {
- if (!mHasLauncherApps || mHasLiveTvFeature) {
+ if (!mHasLauncherApps) {
return;
}
installApp(SIMPLE_APP_APK);
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
new file mode 100644
index 0000000..561d346
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 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_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE_TAGS := optional
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsJdwpSecurityHostTestCases
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_CTS_TEST_PACKAGE := android.host.jdwpsecurity
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jdwpsecurity/app/Android.mk b/hostsidetests/jdwpsecurity/app/Android.mk
new file mode 100644
index 0000000..13b5be4
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/app/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 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_TAGS := optional
+LOCAL_MODULE := CtsJdwpApp
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+include $(BUILD_JAVA_LIBRARY)
+
+# Copy the built module to the cts dir
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+ $(copy-file-to-target)
+
+# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
+$(my_register_name) : $(cts_library_jar)
+
diff --git a/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java b/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java
new file mode 100644
index 0000000..f2e5980
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 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.jdwpsecurity;
+
+public class JdwpTest {
+ private static final long LOOP_TIMEOUT_MS = 60 * 1000;
+
+ public static void main(String[] args) throws Exception {
+ // Print pid so the test knows who we are.
+ int pid = android.os.Process.myPid();
+ System.out.println(pid);
+
+ // Loop to keep alive so the host test has the time to check whether we have a JDWP
+ // connection.
+ // Note: we use a timeout to avoid indefinite loop in case something wrong happens
+ // with the test harness.
+ long start = System.currentTimeMillis();
+ while(getElapsedTime(start) < LOOP_TIMEOUT_MS) {
+ Thread.sleep(100);
+ }
+ }
+
+ private static long getElapsedTime(long start) {
+ return System.currentTimeMillis() - start;
+ }
+}
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
new file mode 100644
index 0000000..8e276ed
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2015 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.jdwpsecurity.cts;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.util.RunUtil;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test to check non-zygote apps do not have an active JDWP connection.
+ */
+public class JdwpSecurityHostTest extends DeviceTestCase implements IBuildReceiver {
+
+ private static final String DEVICE_LOCATION = "/data/local/tmp/jdwpsecurity";
+ private static final String DEVICE_SCRIPT_FILENAME = "jdwptest";
+ private static final String DEVICE_JAR_FILENAME = "CtsJdwpApp.jar";
+ private static final String JAR_MAIN_CLASS_NAME = "com.android.cts.jdwpsecurity.JdwpTest";
+
+ private CtsBuildHelper mCtsBuild;
+
+ private static String getDeviceScriptFilepath() {
+ return DEVICE_LOCATION + File.separator + DEVICE_SCRIPT_FILENAME;
+ }
+
+ private static String getDeviceJarFilepath() {
+ return DEVICE_LOCATION + File.separator + DEVICE_JAR_FILENAME;
+ }
+
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Create test directory on the device.
+ createRemoteDir(DEVICE_LOCATION);
+
+ // Also create the dalvik-cache directory. It needs to exist before the runtime starts.
+ createRemoteDir(DEVICE_LOCATION + File.separator + "dalvik-cache");
+
+ // Create and push script on the device.
+ File tempFile = createScriptTempFile();
+ try {
+ boolean success = getDevice().pushFile(tempFile, getDeviceScriptFilepath());
+ assertTrue("Failed to push script to " + getDeviceScriptFilepath(), success);
+ } finally {
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+ }
+
+ // Make the script executable.
+ getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
+
+ // Push jar file.
+ File jarFile = mCtsBuild.getTestApp(DEVICE_JAR_FILENAME);
+ boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
+ assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ // Delete the whole test directory on the device.
+ getDevice().executeShellCommand(String.format("rm -r %s", DEVICE_LOCATION));
+
+ super.tearDown();
+ }
+
+ /**
+ * Tests a non-zygote app does not have a JDWP connection, thus not being
+ * debuggable.
+ *
+ * Runs a script executing a Java app (jar file) with app_process,
+ * without forking from zygote. Then checks its pid is not returned
+ * by 'adb jdwp', meaning it has no JDWP connection and cannot be
+ * debugged.
+ *
+ * @throws Exception
+ */
+ public void testNonZygoteProgramIsNotDebuggable() throws Exception {
+ String scriptFilepath = getDeviceScriptFilepath();
+ Process scriptProcess = null;
+ String scriptPid = null;
+ List<String> activeJdwpPids = null;
+ try {
+ // Run the script on the background so it's running when we collect the list of
+ // pids with a JDWP connection using 'adb jdwp'.
+ // command.
+ scriptProcess = runScriptInBackground(scriptFilepath);
+
+ // On startup, the script will print its pid on its output.
+ scriptPid = readScriptPid(scriptProcess);
+
+ // Collect the list of pids with a JDWP connection.
+ activeJdwpPids = getJdwpPids();
+ } finally {
+ // Stop the script.
+ if (scriptProcess != null) {
+ scriptProcess.destroy();
+ }
+ }
+
+ assertNotNull("Failed to get script pid", scriptPid);
+ assertNotNull("Failed to get active JDWP pids", activeJdwpPids);
+ assertFalse("Test app should not have an active JDWP connection" +
+ " (pid " + scriptPid + " is returned by 'adb jdwp')",
+ activeJdwpPids.contains(scriptPid));
+ }
+
+ private Process runScriptInBackground(String scriptFilepath) throws IOException {
+ String[] shellScriptCommand = buildAdbCommand("shell", scriptFilepath);
+ return RunUtil.getDefault().runCmdInBackground(shellScriptCommand);
+ }
+
+ private String readScriptPid(Process scriptProcess) throws IOException {
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new InputStreamReader(scriptProcess.getInputStream()));
+ // We only expect to read one line containing the pid.
+ return br.readLine();
+ } finally {
+ if (br != null) {
+ br.close();
+ }
+ }
+ }
+
+ private List<String> getJdwpPids() throws Exception {
+ return new AdbJdwpOutputReader().listPidsWithAdbJdwp();
+ }
+
+ /**
+ * Creates the script file on the host so it can be pushed onto the device.
+ *
+ * @return the script file
+ * @throws IOException
+ */
+ private static File createScriptTempFile() throws IOException {
+ File tempFile = File.createTempFile("jdwptest", ".tmp");
+
+ PrintWriter pw = null;
+ try {
+ pw = new PrintWriter(tempFile);
+
+ // We need a dalvik-cache in /data/local/tmp so we have read-write access.
+ // Note: this will cause the runtime to optimize the DEX file (contained in
+ // the jar file) before executing it.
+ pw.println(String.format("export ANDROID_DATA=%s", DEVICE_LOCATION));
+ pw.println(String.format("export CLASSPATH=%s", getDeviceJarFilepath()));
+ pw.println(String.format("exec app_process /system/bin %s \"$@\"",
+ JAR_MAIN_CLASS_NAME));
+ } finally {
+ if (pw != null) {
+ pw.close();
+ }
+ }
+
+ return tempFile;
+ }
+
+ /**
+ * Helper class collecting all pids returned by 'adb jdwp' command.
+ */
+ private class AdbJdwpOutputReader implements Runnable {
+ /**
+ * A list of all pids with a JDWP connection returned by 'adb jdwp'.
+ */
+ private final List<String> lines = new ArrayList<String>();
+
+ /**
+ * The input stream of the process running 'adb jdwp'.
+ */
+ private InputStream in;
+
+ public List<String> listPidsWithAdbJdwp() throws Exception {
+ // The 'adb jdwp' command does not return normally, it only terminates with Ctrl^C.
+ // Therefore we cannot use ITestDevice.executeAdbCommand but need to run that command
+ // in the background. Since we know the tested app is already running, we only need to
+ // capture the output for a short amount of time before stopping the 'adb jdwp'
+ // command.
+ String[] adbJdwpCommand = buildAdbCommand("jdwp");
+ Process adbProcess = RunUtil.getDefault().runCmdInBackground(adbJdwpCommand);
+ in = adbProcess.getInputStream();
+
+ // Read the output for 5s in a separate thread before stopping the command.
+ Thread t = new Thread(this);
+ t.start();
+ Thread.sleep(5000);
+
+ // Kill the 'adb jdwp' process and wait for the thread to stop.
+ adbProcess.destroy();
+ t.join();
+
+ return lines;
+ }
+
+ @Override
+ public void run() {
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = readLineIgnoreException(br)) != null) {
+ lines.add(line);
+ }
+ } catch (IOException e) {
+ CLog.e(e);
+ } finally {
+ if (br != null) {
+ try {
+ br.close();
+ } catch (IOException e) {
+ // Ignore it.
+ }
+ }
+ }
+ }
+
+ private String readLineIgnoreException(BufferedReader reader) throws IOException {
+ try {
+ return reader.readLine();
+ } catch (IOException e) {
+ if (e instanceof EOFException) {
+ // This is expected when the process's input stream is closed.
+ return null;
+ } else {
+ throw e;
+ }
+ }
+ }
+ }
+
+ private String[] buildAdbCommand(String... args) {
+ return ArrayUtil.buildArray(new String[] {"adb", "-s", getDevice().getSerialNumber()},
+ args);
+ }
+
+ private boolean createRemoteDir(String remoteFilePath) throws DeviceNotAvailableException {
+ if (getDevice().doesFileExist(remoteFilePath)) {
+ return true;
+ }
+ File remoteFile = new File(remoteFilePath);
+ String parentPath = remoteFile.getParent();
+ if (parentPath != null) {
+ if (!createRemoteDir(parentPath)) {
+ return false;
+ }
+ }
+ getDevice().executeShellCommand(String.format("mkdir %s", remoteFilePath));
+ return getDevice().doesFileExist(remoteFilePath);
+ }
+}
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
old mode 100755
new mode 100644
index b31a32d..9e04274
--- a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
@@ -20,7 +20,7 @@
/**
* Base monkey command with flags to avoid side effects like airplane mode.
*/
- static final String MONKEY_CMD = "monkey --pct-motion 0 --pct-majornav 0 --pct-syskeys 0 --pct-anyevent 0 --pct-rotation 0";
+ static final String MONKEY_CMD = "monkey --pct-touch 0 --pct-motion 0 --pct-majornav 0 --pct-syskeys 0 --pct-anyevent 0 --pct-rotation 0";
IAbi mAbi;
CtsBuildHelper mBuild;
diff --git a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
old mode 100644
new mode 100755
index ba880d7..7277b9f
--- a/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
+++ b/hostsidetests/theme/src/android/theme/cts/ComparisonTask.java
@@ -85,6 +85,23 @@
return success;
}
+ private static int getAlphaScaledBlue(final int color) {
+ return (color & 0x000000FF) * getAlpha(color) / 255;
+ }
+
+ private static int getAlphaScaledGreen(final int color) {
+ return ((color & 0x0000FF00) >> 8) * getAlpha(color) / 255;
+ }
+
+ private static int getAlphaScaledRed(final int color) {
+ return ((color & 0x00FF0000) >> 16) * getAlpha(color) / 255;
+ }
+
+ private static int getAlpha(final int color) {
+ // use logical shift for keeping an unsigned value
+ return (color & 0xFF000000) >>> 24;
+ }
+
private static boolean compare(BufferedImage reference, BufferedImage generated, int threshold) {
final int w = generated.getWidth();
final int h = generated.getHeight();
@@ -96,15 +113,14 @@
for (int j = 0; j < h; j++) {
final int p1 = reference.getRGB(i, j);
final int p2 = generated.getRGB(i, j);
- final int dr = (p1 & 0x000000FF) - (p2 & 0x000000FF);
- final int dg = ((p1 & 0x0000FF00) - (p2 & 0x0000FF00)) >> 8;
- final int db = ((p1 & 0x00FF0000) - (p2 & 0x00FF0000)) >> 16;
- final int da = ((p1 & 0xFF000000) - (p2 & 0xFF000000)) >> 24;
+
+ final int dr = getAlphaScaledRed(p1) - getAlphaScaledRed(p2);
+ final int dg = getAlphaScaledGreen(p1) - getAlphaScaledGreen(p2);
+ final int db = getAlphaScaledBlue(p1) - getAlphaScaledBlue(p2);
if (Math.abs(db) > threshold ||
Math.abs(dg) > threshold ||
- Math.abs(dr) > threshold ||
- Math.abs(da) > threshold) {
+ Math.abs(dr) > threshold) {
return false;
}
}
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index 5908923..2ae7b13 100755
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -287,7 +287,7 @@
ex.release();
}
}
- return false;
+ return true;
}
public static boolean checkCodecsForPath(Context context, String path) {
diff --git a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
index bf02d9c..4d1121a 100644
--- a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
+++ b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
@@ -169,8 +169,13 @@
Log.i(TAG, "Encoder " + mimeType + " with " + w + "," + h + " not supported");
return;
}
- CodecInfo infoDec = CodecInfo.getSupportedFormatInfo(mimeType, w, h, false /* encoder */);
- assertNotNull(infoDec);
+
+ CodecInfo infoDec = CodecInfo.getSupportedFormatInfo(mimeType, w, h, false);
+ if (infoDec == null) {
+ Log.i(TAG, "Codec " + mimeType + "with " + w + "," + h + " not supported");
+ return;
+ }
+
mVideoWidth = w;
mVideoHeight = h;
diff --git a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
index 38a753d..a0177e2 100644
--- a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
+++ b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
@@ -34,7 +34,7 @@
private static final String TAG = "MockJobService";
/** Wait this long before timing out the test. */
- private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
+ private static final long DEFAULT_TIMEOUT_MILLIS = 5000L; // 5 seconds.
@Override
public void onCreate() {
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
index ed9cadd..36f44ef 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TimingConstraintsTest.java
@@ -29,7 +29,7 @@
public void testScheduleOnce() throws Exception {
JobInfo oneTimeJob = new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
- .setOverrideDeadline(5000) // 5 secs
+ .setOverrideDeadline(1000) // 1 secs
.build();
kTestEnvironment.setExpectedExecutions(1);
@@ -41,7 +41,7 @@
public void testSchedulePeriodic() throws Exception {
JobInfo periodicJob =
new JobInfo.Builder(TIMING_JOB_ID, kJobServiceComponent)
- .setPeriodic(5000L) // 5 second period.
+ .setPeriodic(1000L) // 1 second period.
.build();
kTestEnvironment.setExpectedExecutions(3);
@@ -52,8 +52,7 @@
public void testCancel() throws Exception {
JobInfo cancelJob = new JobInfo.Builder(CANCEL_JOB_ID, kJobServiceComponent)
- .setMinimumLatency(5000L) // make sure it doesn't actually run immediately
- .setOverrideDeadline(7000L)
+ .setOverrideDeadline(2000L)
.build();
kTestEnvironment.setExpectedExecutions(0);
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 76b528b..5057725 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -1,12 +1,5 @@
[
{
- description: "testWindowContentFrameStats is flaky without 75b55d0846159543aafc1b7420915497fce9b3f1",
- names: [
- "android.app.uiautomation.cts.UiAutomationTest#testWindowContentFrameStats"
- ],
- bug: 18039218
-},
-{
description: "the UsageStats is not yet stable enough",
names: [
"android.app.usage.cts.UsageStatsTest"
@@ -336,17 +329,10 @@
bug: 18030049
},
{
- description: "The new recording test is not yet passing on all devices",
+ description: "EventOrderingVerificationTest not working.",
names: [
- "android.hardware.camera2.cts.RecordingTest#testRecordingFramerateLowToHigh"
+ "android.hardware.cts.helpers.sensorverification.EventOrderingVerificationTest#testSameTimestamp"
],
- bug: 18705837
-},
-{
- description: "The new image reader test is not yet passing on all devices",
- names: [
- "android.hardware.camera2.cts.ImageReaderTest#testAllOutputYUVResolutions"
- ],
- bug: 18689511
+ bug: 23792027
}
]
diff --git a/tests/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml b/tests/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml
index 9906227..229dbfe 100644
--- a/tests/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml
+++ b/tests/tests/accessibilityservice/res/layout/accessibility_text_traversal_test.xml
@@ -42,13 +42,13 @@
<EditText
android:id="@+id/edit"
- android:layout_width="80dip"
+ android:layout_width="64dip"
android:layout_height="80dip"
android:maxLines="1000"
android:scrollbars="vertical"
android:focusable="false"
android:includeFontPadding="false"
- android:textSize="10dip"
+ android:textSize="8dip"
android:textStyle="normal"
android:fontFamily="sans-serif"
android:visibility="gone"
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
index 5deff5a..88828ea 100644
--- a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -135,8 +135,8 @@
}
private void assertMemoryForScreenDensity(int memoryClass, int screenDensity, int screenSize) {
- int expectedMinimumMemory = ExpectedMemorySizesClass.getExpectedMemorySize(screenSize,
- screenDensity);
+ int expectedMinimumMemory = ExpectedMemorySizesClass.getExpectedMemorySize(screenDensity,
+ screenSize);
assertTrue("Expected to have at least " + expectedMinimumMemory
+ "mb of memory for screen density " + screenDensity,
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerTest.java
index 998a005..e633f1f 100644
--- a/tests/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -219,8 +219,7 @@
hasTestProcess = true;
}
}
- // For security reasons the system process is not exposed.
- assertTrue(!hasSystemProcess && hasTestProcess);
+ assertTrue(hasSystemProcess && hasTestProcess);
for (RunningAppProcessInfo ra : list) {
if (ra.processName.equals("com.android.cts.app.stub:remote")) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 43ac33b..29c7362 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -1325,10 +1325,6 @@
!mStaticInfo.isCapabilitySupported(CameraCharacteristics.
REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
// OK
- } else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG &&
- !mStaticInfo.isCapabilitySupported(CameraCharacteristics.
- REQUEST_AVAILABLE_CAPABILITIES_ZSL)) {
- // OK.
} else if (sLegacySkipTemplates.contains(template) &&
mStaticInfo.isHardwareLevelLegacy()) {
// OK
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
index b4113e5..2554b17 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -426,10 +426,6 @@
waitForNumResults(resultListener, NUM_FRAMES_WAITED);
stopPreview();
-
- // Free image resources
- image.close();
- closeImageReader();
return;
}
@@ -599,9 +595,6 @@
Image image = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
validateJpegCapture(image, maxStillSz);
- // Free image resources
- image.close();
-
stopPreview();
}
@@ -648,10 +641,6 @@
Image image = imageListener.getImage((mStaticInfo.isHardwareLevelLegacy()) ?
RELAXED_CAPTURE_IMAGE_TIMEOUT_MS : CAPTURE_IMAGE_TIMEOUT_MS);
validateJpegCapture(image, stillSz);
-
- // Free image resources
- image.close();
-
// stopPreview must be called here to make sure next time a preview stream
// is created with new size.
stopPreview();
@@ -702,9 +691,6 @@
dumpFile(rawFileName, rawBuffer);
}
- // Free image resources
- image.close();
-
stopPreview();
}
@@ -1022,9 +1008,6 @@
if (!mStaticInfo.isHardwareLevelLegacy()) {
jpegTestExifExtraTags(exif, maxStillSz, stillResult);
}
-
- // Free image resources
- image.close();
}
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
old mode 100755
new mode 100644
index f2a9aee..00f7e1c
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -96,7 +96,6 @@
protected CameraCaptureSession mSession;
protected ImageReader mReader;
protected Surface mReaderSurface;
- protected Surface mOldReaderSurface;
protected Surface mPreviewSurface;
protected Size mPreviewSize;
protected List<Size> mOrderedPreviewSizes; // In descending order.
@@ -550,8 +549,6 @@
protected void closeImageReader() {
CameraTestUtils.closeImageReader(mReader);
mReader = null;
- Log.i(TAG,"mReaderSurface = " + mReaderSurface);
- mOldReaderSurface = mReaderSurface;
mReaderSurface = null;
}
@@ -657,11 +654,7 @@
outputSurfaces.add(mReaderSurface);
mSessionListener = new BlockingSessionCallback();
mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
- if (mOldReaderSurface != null) {
- Log.i(TAG,"release mOldReaderSurface = " + mOldReaderSurface);
- mOldReaderSurface.release();
- mOldReaderSurface = null;
- }
+
// Configure the requests.
previewRequest.addTarget(mPreviewSurface);
stillRequest.addTarget(mPreviewSurface);
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
index 68efef0..a2ddb4d 100755
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -105,7 +105,7 @@
if (supports64Bit) {
assertMinMemoryMb(1824);
} else {
- assertMinMemoryMb(1344);
+ assertMinMemoryMb(1099);
}
} else if (greaterThanDpi(density, DENSITY_400, screenSize,
SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index d572c8a..162474a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -357,7 +357,7 @@
// TODO: after L release move to SensorBatchingTests and run in all sensors with default
// verifications enabled
- public void testBatchAndFlushWithMutipleSensors() throws Exception {
+ public void testBatchAndFlushWithMultipleSensors() throws Exception {
final int maxSensors = 3;
final int maxReportLatencyUs = (int) TimeUnit.SECONDS.toMicros(10);
List<Sensor> sensorsToTest = new ArrayList<Sensor>();
diff --git a/tests/tests/media/res/raw/gb18030_5.mp3 b/tests/tests/media/res/raw/gb18030_5.mp3
deleted file mode 100644
index 70f76ce..0000000
--- a/tests/tests/media/res/raw/gb18030_5.mp3
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/heap_oob_flac.mp3 b/tests/tests/media/res/raw/heap_oob_flac.mp3
new file mode 100644
index 0000000..ae542d0
--- /dev/null
+++ b/tests/tests/media/res/raw/heap_oob_flac.mp3
Binary files differ
diff --git a/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4 b/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
new file mode 100644
index 0000000..110c0d6
--- /dev/null
+++ b/tests/tests/media/res/raw/on_input_buffer_filled_sigsegv.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
new file mode 100644
index 0000000..7b663a4
--- /dev/null
+++ b/tests/tests/media/res/raw/video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
deleted file mode 100644
index 9277fbd..0000000
--- a/tests/tests/media/res/raw/video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 969963d..c347282 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -1319,13 +1319,11 @@
/* test if the explicitly named codec is present on the system */
if (explicitCodecName != null) {
- try {
- MediaCodec codec = MediaCodec.createByCodecName(explicitCodecName);
- if (codec != null) {
- codec.release();
- add(new Codec(explicitCodecName, null, mediaList));
- }
- } catch (Exception e) {}
+ MediaCodec codec = MediaCodec.createByCodecName(explicitCodecName);
+ if (codec != null) {
+ codec.release();
+ add(new Codec(explicitCodecName, null, mediaList));
+ }
}
} catch (Throwable t) {
Log.wtf("Constructor failed", t);
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index f58e6ab..f7fcd0a 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -38,6 +38,7 @@
import com.android.cts.media.R;
+
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioManager;
@@ -49,18 +50,13 @@
import android.test.AndroidTestCase;
import android.view.SoundEffectConstants;
-import java.util.TreeMap;
-
public class AudioManagerTest extends AndroidTestCase {
private final static int MP3_TO_PLAY = R.raw.testmp3;
private final static long TIME_TO_PLAY = 2000;
private AudioManager mAudioManager;
private boolean mHasVibrator;
- private boolean mUseMasterVolume;
private boolean mUseFixedVolume;
- private int[] mMasterVolumeRamp;
- private TreeMap<Integer, Integer> mMasterVolumeMap = new TreeMap<Integer, Integer>();
private boolean mIsTelevision;
@Override
@@ -69,16 +65,8 @@
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = (vibrator != null) && vibrator.hasVibrator();
- mUseMasterVolume = mContext.getResources().getBoolean(
- Resources.getSystem().getIdentifier("config_useMasterVolume", "bool", "android"));
mUseFixedVolume = mContext.getResources().getBoolean(
Resources.getSystem().getIdentifier("config_useFixedVolume", "bool", "android"));
- mMasterVolumeRamp = mContext.getResources().getIntArray(
- Resources.getSystem().getIdentifier("config_masterVolumeRamp", "array", "android"));
- assertTrue((mMasterVolumeRamp.length > 0) && (mMasterVolumeRamp.length % 2 == 0));
- for (int i = 0; i < mMasterVolumeRamp.length; i+=2) {
- mMasterVolumeMap.put(mMasterVolumeRamp[i], mMasterVolumeRamp[i+1]);
- }
PackageManager packageManager = mContext.getPackageManager();
mIsTelevision = packageManager != null
&& (packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
@@ -334,7 +322,6 @@
}
public void testVolume() throws Exception {
- int volume, volumeDelta;
int[] streams = { AudioManager.STREAM_ALARM,
AudioManager.STREAM_MUSIC,
AudioManager.STREAM_VOICE_CALL,
@@ -377,32 +364,22 @@
mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
assertEquals(maxVolume, mAudioManager.getStreamVolume(streams[i]));
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
mAudioManager.adjustSuggestedStreamVolume(ADJUST_LOWER, streams[i], 0);
- assertEquals(maxVolume - volumeDelta, mAudioManager.getStreamVolume(streams[i]));
+ assertEquals(maxVolume - 1, mAudioManager.getStreamVolume(streams[i]));
// volume lower
mAudioManager.setStreamVolume(streams[i], maxVolume, 0);
- volume = mAudioManager.getStreamVolume(streams[i]);
- while (volume > 0) {
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
+ for (int k = maxVolume; k > 0; k--) {
mAudioManager.adjustStreamVolume(streams[i], ADJUST_LOWER, 0);
- assertEquals(Math.max(0, volume - volumeDelta),
- mAudioManager.getStreamVolume(streams[i]));
- volume = mAudioManager.getStreamVolume(streams[i]);
+ assertEquals(k - 1, mAudioManager.getStreamVolume(streams[i]));
}
mAudioManager.adjustStreamVolume(streams[i], ADJUST_SAME, 0);
-
// volume raise
mAudioManager.setStreamVolume(streams[i], 1, 0);
- volume = mAudioManager.getStreamVolume(streams[i]);
- while (volume < maxVolume) {
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(streams[i]));
+ for (int k = 1; k < maxVolume; k++) {
mAudioManager.adjustStreamVolume(streams[i], ADJUST_RAISE, 0);
- assertEquals(Math.min(volume + volumeDelta, maxVolume),
- mAudioManager.getStreamVolume(streams[i]));
- volume = mAudioManager.getStreamVolume(streams[i]);
+ assertEquals(1 + k, mAudioManager.getStreamVolume(streams[i]));
}
// volume same
@@ -437,20 +414,18 @@
}
// adjust volume as ADJUST_RAISE
- mAudioManager.setStreamVolume(STREAM_MUSIC, 0, 0);
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
- mAudioManager.adjustVolume(ADJUST_RAISE, 0);
- assertEquals(Math.min(volumeDelta, maxMusicVolume),
- mAudioManager.getStreamVolume(STREAM_MUSIC));
+ mAudioManager.setStreamVolume(STREAM_MUSIC, 1, 0);
+ for (int k = 0; k < maxMusicVolume - 1; k++) {
+ mAudioManager.adjustVolume(ADJUST_RAISE, 0);
+ assertEquals(2 + k, mAudioManager.getStreamVolume(STREAM_MUSIC));
+ }
// adjust volume as ADJUST_LOWER
mAudioManager.setStreamVolume(STREAM_MUSIC, maxMusicVolume, 0);
maxMusicVolume = mAudioManager.getStreamVolume(STREAM_MUSIC);
- volumeDelta = getVolumeDelta(mAudioManager.getStreamVolume(STREAM_MUSIC));
- mAudioManager.adjustVolume(ADJUST_LOWER, 0);
- assertEquals(Math.max(0, maxMusicVolume - volumeDelta),
- mAudioManager.getStreamVolume(STREAM_MUSIC));
+ mAudioManager.adjustVolume(ADJUST_LOWER, 0);
+ assertEquals(maxMusicVolume - 1, mAudioManager.getStreamVolume(STREAM_MUSIC));
mp.stop();
mp.release();
Thread.sleep(TIME_TO_PLAY);
@@ -465,13 +440,4 @@
mAudioManager.setRingerMode(-3007);
assertEquals(ringerMode, mAudioManager.getRingerMode());
}
-
- private int getVolumeDelta(int volume) {
- if (!mUseMasterVolume) {
- return 1;
- }
- int volumeDelta = mMasterVolumeMap.floorEntry(volume).getValue();
- assertTrue(volumeDelta > 0);
- return volumeDelta;
- }
}
diff --git a/tests/tests/media/src/android/media/cts/CodecState.java b/tests/tests/media/src/android/media/cts/CodecState.java
index 8f62227..db10cd1 100644
--- a/tests/tests/media/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/src/android/media/cts/CodecState.java
@@ -255,6 +255,9 @@
Log.d(TAG, "saw input EOS on track " + mTrackIndex);
mSawInputEOS = true;
+ if (mTunneled && !mIsAudio) {
+ mSawOutputEOS = true;
+ }
mCodec.queueInputBuffer(
index, 0 /* offset */, 0 /* sampleSize */,
@@ -328,12 +331,10 @@
if (mAudioTrack != null) {
ByteBuffer buffer = mCodecOutputBuffers[index];
buffer.clear();
- buffer.position(0 /* offset */);
+ ByteBuffer audioBuffer = ByteBuffer.allocate(buffer.remaining());
+ audioBuffer.put(buffer);
- byte[] audioCopy = new byte[info.size];
- buffer.get(audioCopy, 0, info.size);
-
- mAudioTrack.write(audioCopy, info.size);
+ mAudioTrack.write(audioBuffer, info.size, info.presentationTimeUs*1000);
mCodec.releaseOutputBuffer(index, false /* render */);
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 40e619b..1c9e4b9 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -1094,8 +1094,8 @@
testDecode(R.raw.video_1920x1080_mp4_hevc_10240kbps_30fps_aac_stereo_128kbps_44100hz, 299);
}
- public void testHEVCDecode30fps3840x2160() throws Exception {
- testDecode(R.raw.video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz, 299);
+ public void testHEVCDecode30fps2840x2160() throws Exception {
+ testDecode(R.raw.video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz, 299);
}
private void testCodecEarlyEOS(int resid, int eosFrame) throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
index 029a632..14f8b9b 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -20,6 +20,8 @@
import android.content.res.AssetFileDescriptor;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
@@ -29,6 +31,10 @@
import android.util.Log;
import android.view.Surface;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.CodecProfileLevel;
+
import com.android.cts.media.R;
import java.io.File;
@@ -111,28 +117,28 @@
private String mOutputFile;
public void testExtractDecodeEditEncodeMuxQCIF() throws Throwable {
- setSize(176, 144);
+ if(!setSize(176, 144)) return;
setSource(R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz);
setCopyVideo();
TestWrapper.runTest(this);
}
public void testExtractDecodeEditEncodeMuxQVGA() throws Throwable {
- setSize(320, 240);
+ if(!setSize(320, 240)) return;
setSource(R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz);
setCopyVideo();
TestWrapper.runTest(this);
}
public void testExtractDecodeEditEncodeMux720p() throws Throwable {
- setSize(1280, 720);
+ if(!setSize(1280, 720)) return;
setSource(R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz);
setCopyVideo();
TestWrapper.runTest(this);
}
public void testExtractDecodeEditEncodeMuxAudio() throws Throwable {
- setSize(1280, 720);
+ if(!setSize(1280, 720)) return;
setSource(R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz);
setCopyAudio();
setVerifyAudioFormat();
@@ -140,7 +146,7 @@
}
public void testExtractDecodeEditEncodeMuxAudioVideo() throws Throwable {
- setSize(1280, 720);
+ if(!setSize(1280, 720)) return;
setSource(R.raw.video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz);
setCopyAudio();
setCopyVideo();
@@ -203,14 +209,20 @@
}
/**
- * Sets the desired frame size.
- */
- private void setSize(int width, int height) {
+ * Sets the desired frame size and returns whether the given resolution is
+ * supported.
+ *
+ * <p>If decoding/encoding using AVC as the codec, checks that the resolution
+ * is supported. For other codecs, always return {@code true}.
+ */
+ private boolean setSize(int width, int height) {
if ((width % 16) != 0 || (height % 16) != 0) {
Log.w(TAG, "WARNING: width or height not multiple of 16");
}
mWidth = width;
mHeight = height;
+
+ return isAvcSupportedSize(width, height);
}
/**
@@ -1130,4 +1142,87 @@
private static String getMimeTypeFor(MediaFormat format) {
return format.getString(MediaFormat.KEY_MIME);
}
+
+ /**
+ * Returns the first codec capable of encoding the specified MIME type, or null if no match was
+ * found.
+ */
+ private static MediaCodecInfo selectCodec(String mimeType) {
+ int numCodecs = MediaCodecList.getCodecCount();
+ for (int i = 0; i < numCodecs; i++) {
+ MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
+
+ if (!codecInfo.isEncoder()) {
+ continue;
+ }
+
+ String[] types = codecInfo.getSupportedTypes();
+ for (int j = 0; j < types.length; j++) {
+ if (types[j].equalsIgnoreCase(mimeType)) {
+ return codecInfo;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the given resolution is supported by the AVC codec.
+ */
+ private static boolean isAvcSupportedSize(int width, int height) {
+ MediaCodecInfo mediaCodecInfo = selectCodec(OUTPUT_VIDEO_MIME_TYPE);
+ CodecCapabilities cap = mediaCodecInfo.getCapabilitiesForType(OUTPUT_VIDEO_MIME_TYPE);
+ if (cap == null) { // not supported
+ return false;
+ }
+ int highestLevel = 0;
+ for (CodecProfileLevel lvl : cap.profileLevels) {
+ if (lvl.level > highestLevel) {
+ highestLevel = lvl.level;
+ }
+ }
+ int maxW = 0;
+ int maxH = 0;
+ int bitRate = 0;
+ int fps = 0; // frame rate for the max resolution
+ switch(highestLevel) {
+ // Do not support Level 1 to 2.
+ case CodecProfileLevel.AVCLevel1:
+ case CodecProfileLevel.AVCLevel11:
+ case CodecProfileLevel.AVCLevel12:
+ case CodecProfileLevel.AVCLevel13:
+ case CodecProfileLevel.AVCLevel1b:
+ case CodecProfileLevel.AVCLevel2:
+ return false;
+ case CodecProfileLevel.AVCLevel21:
+ maxW = 352;
+ maxH = 576;
+ break;
+ case CodecProfileLevel.AVCLevel22:
+ maxW = 720;
+ maxH = 480;
+ break;
+ case CodecProfileLevel.AVCLevel3:
+ maxW = 720;
+ maxH = 480;
+ break;
+ case CodecProfileLevel.AVCLevel31:
+ maxW = 1280;
+ maxH = 720;
+ break;
+ case CodecProfileLevel.AVCLevel32:
+ maxW = 1280;
+ maxH = 720;
+ break;
+ case CodecProfileLevel.AVCLevel4: // only try up to 1080p
+ default:
+ maxW = 1920;
+ maxH = 1080;
+ break;
+ }
+ if(maxW*maxH < width*height)
+ return false;
+ else
+ return true;
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index e058981..b07df8b 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -21,6 +21,7 @@
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.cts.util.MediaUtils;
+import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaCodec;
import android.media.MediaExtractor;
@@ -45,6 +46,7 @@
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.Vector;
@@ -89,6 +91,49 @@
}
}
+ public void testonInputBufferFilledSigsegv() throws Exception {
+ testIfMediaServerDied(R.raw.on_input_buffer_filled_sigsegv);
+ }
+
+ public void testFlacHeapOverflow() throws Exception {
+ testIfMediaServerDied(R.raw.heap_oob_flac);
+ }
+
+ private void testIfMediaServerDied(int res) throws Exception {
+ mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ assertTrue(mp == mMediaPlayer);
+ assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
+ Log.w(LOG_TAG, "onError " + what);
+ return false;
+ }
+ });
+
+ mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ assertTrue(mp == mMediaPlayer);
+ mOnCompletionCalled.signal();
+ }
+ });
+
+ AssetFileDescriptor afd = mResources.openRawResourceFd(res);
+ mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ try {
+ mMediaPlayer.prepare();
+ mMediaPlayer.start();
+ if (!mOnCompletionCalled.waitForSignal(5000)) {
+ Log.w(LOG_TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
+ }
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "playback failed", e);
+ } finally {
+ mMediaPlayer.release();
+ }
+ }
+
// Bug 13652927
public void testVorbisCrash() throws Exception {
MediaPlayer mp = mMediaPlayer;
@@ -773,15 +818,34 @@
return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
+ private Camera mCamera;
private void testRecordedVideoPlaybackWithAngle(int angle) throws Exception {
- final int width = RECORDED_VIDEO_WIDTH;
- final int height = RECORDED_VIDEO_HEIGHT;
+ int width = RECORDED_VIDEO_WIDTH;
+ int height = RECORDED_VIDEO_HEIGHT;
final String file = RECORDED_FILE;
final long durationMs = RECORDED_DURATION_MS;
if (!hasCamera()) {
return;
}
+
+ boolean isSupported = false;
+ mCamera = Camera.open(0);
+ Camera.Parameters parameters = mCamera.getParameters();
+ List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+ for (Camera.Size size : previewSizes)
+ {
+ if (size.width == width && size.height == height) {
+ isSupported = true;
+ break;
+ }
+ }
+ mCamera.release();
+ mCamera = null;
+ if (!isSupported) {
+ width = previewSizes.get(0).width;
+ height = previewSizes.get(0).height;
+ }
checkOrientation(angle);
recordVideo(width, height, angle, file, durationMs);
checkDisplayedVideoSize(width, height, angle, file);
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index 216e21b..8c8215e 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -20,6 +20,7 @@
import android.cts.util.MediaUtils;
import android.hardware.Camera;
import android.media.MediaFormat;
+import android.media.CamcorderProfile;
import android.media.MediaMetadataRetriever;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnErrorListener;
@@ -38,6 +39,7 @@
import java.io.FileOutputStream;
import java.lang.InterruptedException;
import java.lang.Runnable;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -52,6 +54,8 @@
private static final int RECORDED_DUR_TOLERANCE_MS = 1000;
private static final int VIDEO_WIDTH = 176;
private static final int VIDEO_HEIGHT = 144;
+ private static int mVideoWidth = VIDEO_WIDTH;
+ private static int mVideoHeight = VIDEO_HEIGHT;
private static final int VIDEO_BIT_RATE_IN_BPS = 128000;
private static final double VIDEO_TIMELAPSE_CAPTURE_RATE_FPS = 1.0;
private static final int AUDIO_BIT_RATE_IN_BPS = 12200;
@@ -165,19 +169,17 @@
if (!hasCamera()) {
return;
}
- // Try to get camera first supported resolution.
- // If we fail for any reason, set the video size to default value.
- try {
- camera = Camera.open();
- width = camera.getParameters().getSupportedPreviewSizes().get(0).width;
- height = camera.getParameters().getSupportedPreviewSizes().get(0).height;
- } catch (Exception e) {
+ // Try to get camera profile for QUALITY_LOW; if unavailable,
+ // set the video size to default value.
+ CamcorderProfile profile = CamcorderProfile.get(
+ 0 /* cameraId */, CamcorderProfile.QUALITY_LOW);
+ if (profile != null) {
+ width = profile.videoFrameWidth;
+ height = profile.videoFrameHeight;
+ } else {
width = VIDEO_WIDTH;
height = VIDEO_HEIGHT;
}
- if (camera != null) {
- camera.release();
- }
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
@@ -205,6 +207,7 @@
int durMs = timelapse? RECORD_TIME_LAPSE_MS: RECORD_TIME_MS;
for (int cameraId = 0; cameraId < nCamera; cameraId++) {
mCamera = Camera.open(cameraId);
+ setSupportedResolution(mCamera);
recordVideoUsingCamera(mCamera, OUTPUT_PATH, durMs, timelapse);
mCamera.release();
mCamera = null;
@@ -212,6 +215,21 @@
}
}
+ private void setSupportedResolution(Camera camera) {
+ Camera.Parameters parameters = camera.getParameters();
+ List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
+ for (Camera.Size size : previewSizes)
+ {
+ if (size.width == VIDEO_WIDTH && size.height == VIDEO_HEIGHT) {
+ mVideoWidth = VIDEO_WIDTH;
+ mVideoHeight = VIDEO_HEIGHT;
+ return;
+ }
+ }
+ mVideoWidth = previewSizes.get(0).width;
+ mVideoHeight = previewSizes.get(0).height;
+ }
+
private void recordVideoUsingCamera(
Camera camera, String fileName, int durMs, boolean timelapse) throws Exception {
// FIXME:
@@ -228,7 +246,7 @@
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mMediaRecorder.setVideoFrameRate(frameRate);
- mMediaRecorder.setVideoSize(VIDEO_WIDTH, VIDEO_HEIGHT);
+ mMediaRecorder.setVideoSize(mVideoWidth, mVideoHeight);
mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
mMediaRecorder.setOutputFile(fileName);
mMediaRecorder.setLocation(LATITUDE, LONGITUDE);
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index 4b42690..af7cfaa 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -390,8 +390,6 @@
new String[] {"电视原声带", "格斗天王(限量精装版)(预购版)", null, "11.Open Arms.( cn808.net )", null} ),
new MediaScanEntry(R.raw.gb18030_4,
new String[] {"莫扎特", "黄金古典", "柏林爱乐乐团", "第25号交响曲", "莫扎特"} ),
- new MediaScanEntry(R.raw.gb18030_5,
- new String[] {"光良", "童话", "光良", "02.童话", "鍏夎壇"} ),
new MediaScanEntry(R.raw.gb18030_6,
new String[] {"张韶涵", "潘朵拉", "張韶涵", "隐形的翅膀", "王雅君"} ),
new MediaScanEntry(R.raw.gb18030_7, // this is actually utf-8
diff --git a/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java b/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
index 20c1dff..86bab41 100644
--- a/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
+++ b/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
@@ -21,6 +21,8 @@
import android.media.AudioAttributes;
import android.util.Log;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.LinkedList;
/**
@@ -32,20 +34,15 @@
public class NonBlockingAudioTrack {
private static final String TAG = NonBlockingAudioTrack.class.getSimpleName();
- class QueueElem {
- byte[] data;
- int offset;
+ class QueueElement {
+ ByteBuffer data;
int size;
}
private AudioTrack mAudioTrack;
- private boolean mWriteMorePending = false;
private int mSampleRate;
- private int mFrameSize;
- private int mBufferSizeInFrames;
- private int mNumFramesSubmitted = 0;
private int mNumBytesQueued = 0;
- private LinkedList<QueueElem> mQueue = new LinkedList<QueueElem>();
+ private LinkedList<QueueElement> mQueue = new LinkedList<QueueElement>();
public NonBlockingAudioTrack(int sampleRate, int channelCount, boolean hwAvSync,
int audioSessionId) {
@@ -97,8 +94,6 @@
}
mSampleRate = sampleRate;
- mFrameSize = 2 * channelCount;
- mBufferSizeInFrames = bufferSize / mFrameSize;
}
public long getAudioTimeUs() {
@@ -116,18 +111,13 @@
}
public void stop() {
- cancelWriteMore();
-
mAudioTrack.stop();
- mNumFramesSubmitted = 0;
mQueue.clear();
mNumBytesQueued = 0;
}
public void pause() {
- cancelWriteMore();
-
mAudioTrack.pause();
}
@@ -136,95 +126,67 @@
return;
}
mAudioTrack.flush();
- mNumFramesSubmitted = 0;
mQueue.clear();
mNumBytesQueued = 0;
}
public void release() {
- cancelWriteMore();
-
+ mQueue.clear();
+ mNumBytesQueued = 0;
mAudioTrack.release();
mAudioTrack = null;
}
public void process() {
- mWriteMorePending = false;
- writeMore();
+ while (!mQueue.isEmpty()) {
+ QueueElement element = mQueue.peekFirst();
+ int written = mAudioTrack.write(element.data, element.size,
+ AudioTrack.WRITE_NON_BLOCKING);
+ if (written < 0) {
+ throw new RuntimeException("Audiotrack.write() failed.");
+ }
+
+ mNumBytesQueued -= written;
+ element.size -= written;
+ if (element.size != 0) {
+ break;
+ }
+ mQueue.removeFirst();
+ }
}
public int getPlayState() {
return mAudioTrack.getPlayState();
}
- private void writeMore() {
- if (mQueue.isEmpty()) {
- return;
- }
+ public void write(ByteBuffer data, int size, long pts) {
+ // create timestamp header
+ final int headerSize = 16;
+ ByteBuffer avSyncHeader;
+ avSyncHeader = ByteBuffer.allocate(headerSize);
+ avSyncHeader.order(ByteOrder.BIG_ENDIAN);
+ avSyncHeader.putInt(0x55550001);
+ avSyncHeader.putInt(size);
+ avSyncHeader.putLong(pts);
+ avSyncHeader.position(0);
- int numFramesPlayed = mAudioTrack.getPlaybackHeadPosition();
- int numFramesPending = mNumFramesSubmitted - numFramesPlayed;
- int numFramesAvailableToWrite = mBufferSizeInFrames - numFramesPending;
- int numBytesAvailableToWrite = numFramesAvailableToWrite * mFrameSize;
+ QueueElement headerElement = new QueueElement();
+ headerElement.data = avSyncHeader;
+ headerElement.size = headerSize;
- while (numBytesAvailableToWrite > 0) {
- QueueElem elem = mQueue.peekFirst();
+ // accumulate size written to queue
+ mNumBytesQueued += headerSize;
+ mQueue.add(headerElement);
- int numBytes = elem.size;
- if (numBytes > numBytesAvailableToWrite) {
- numBytes = numBytesAvailableToWrite;
- }
-
- int written = mAudioTrack.write(elem.data, elem.offset, numBytes);
- assert(written == numBytes);
-
- mNumFramesSubmitted += written / mFrameSize;
-
- elem.size -= numBytes;
- numBytesAvailableToWrite -= numBytes;
- mNumBytesQueued -= numBytes;
-
- if (elem.size == 0) {
- mQueue.removeFirst();
-
- if (mQueue.isEmpty()) {
- break;
- }
- } else {
- elem.offset += numBytes;
- }
- }
-
- if (!mQueue.isEmpty()) {
- scheduleWriteMore();
- }
- }
-
- private void scheduleWriteMore() {
- if (mWriteMorePending) {
- return;
- }
-
- int numFramesPlayed = mAudioTrack.getPlaybackHeadPosition();
- int numFramesPending = mNumFramesSubmitted - numFramesPlayed;
- int pendingDurationMs = 1000 * numFramesPending / mSampleRate;
-
- mWriteMorePending = true;
- }
-
- private void cancelWriteMore() {
- mWriteMorePending = false;
- }
-
- public void write(byte[] data, int size) {
- QueueElem elem = new QueueElem();
- elem.data = data;
- elem.offset = 0;
- elem.size = size;
+ // create payload element
+ QueueElement element = new QueueElement();
+ element.data = data;
+ element.size = size;
+ data.position(0);
// accumulate size written to queue
mNumBytesQueued += size;
- mQueue.add(elem);
+ mQueue.add(element);
}
}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 9daf3c4..538a832 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,16 +16,21 @@
package android.net.cts;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
+import android.net.NetworkRequest;
import android.net.wifi.WifiManager;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -343,4 +348,23 @@
return mReceiveLatch.await(30, TimeUnit.SECONDS);
}
}
+
+ /** Verify restricted networks cannot be requested. */
+ public void testRestrictedNetworks() {
+ // Verify we can request unrestricted networks:
+ NetworkRequest request = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET).build();
+ NetworkCallback callback = new NetworkCallback();
+ mCm.requestNetwork(request, callback);
+ mCm.unregisterNetworkCallback(callback);
+ // Verify we cannot request restricted networks:
+ request = new NetworkRequest.Builder().addCapability(NET_CAPABILITY_IMS).build();
+ callback = new NetworkCallback();
+ try {
+ mCm.requestNetwork(request, callback);
+ fail("No exception thrown when restricted network requested.");
+ } catch (SecurityException e) {
+ // Expected.
+ }
+ }
}
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 8ed74ba..9086b0b 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -22,6 +22,7 @@
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 46d0868..c7d854c 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -32,7 +32,10 @@
android_security_cts_SELinuxTest.cpp \
android_security_cts_MMapExecutableTest.cpp \
android_security_cts_NetlinkSocket.cpp \
- android_security_cts_AudioPolicyBinderTest.cpp
+ android_security_cts_AudioPolicyBinderTest.cpp \
+ android_security_cts_AudioFlingerBinderTest.cpp \
+ android_security_cts_MediaPlayerInfoLeakTest.cpp \
+ android_security_cts_AudioEffectBinderTest.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
diff --git a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
index ca8e841..e16f06b 100644
--- a/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
+++ b/tests/tests/security/jni/CtsSecurityJniOnLoad.cpp
@@ -27,6 +27,9 @@
extern int register_android_security_cts_SELinuxTest(JNIEnv*);
extern int register_android_security_cts_MMapExecutableTest(JNIEnv* env);
extern int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env);
+extern int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env);
+extern int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env);
+extern int register_android_security_cts_AudioEffectBinderTest(JNIEnv* env);
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
@@ -75,5 +78,17 @@
return JNI_ERR;
}
+ if (register_android_security_cts_AudioFlingerBinderTest(env)) {
+ return JNI_ERR;
+ }
+
+ if (register_android_security_cts_MediaPlayerInfoLeakTest(env)) {
+ return JNI_ERR;
+ }
+
+ if (register_android_security_cts_AudioEffectBinderTest(env)) {
+ return JNI_ERR;
+ }
+
return JNI_VERSION_1_4;
}
diff --git a/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
new file mode 100644
index 0000000..25f3f80
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_AudioEffectBinderTest.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 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 LOG_TAG "AudioEffectBinderTest-JNI"
+
+#include <jni.h>
+#include <media/AudioEffect.h>
+#include <media/IEffect.h>
+
+using namespace android;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
+ */
+
+struct EffectClient : public BnEffectClient {
+ EffectClient() { }
+ virtual void controlStatusChanged(bool controlGranted __unused) { }
+ virtual void enableStatusChanged(bool enabled __unused) { }
+ virtual void commandExecuted(uint32_t cmdCode __unused,
+ uint32_t cmdSize __unused,
+ void *pCmdData __unused,
+ uint32_t replySize __unused,
+ void *pReplyData __unused) { }
+};
+
+struct DeathRecipient : public IBinder::DeathRecipient {
+ DeathRecipient() : mDied(false) { }
+ virtual void binderDied(const wp<IBinder>& who __unused) { mDied = true; }
+ bool died() const { return mDied; }
+ bool mDied;
+};
+
+static bool isIEffectCommandSecure(IEffect *effect)
+{
+ // some magic constants here
+ const int COMMAND_SIZE = 1024 + 12; // different than reply size to get different heap frag
+ char cmdData[COMMAND_SIZE];
+ memset(cmdData, 0xde, sizeof(cmdData));
+
+ const int REPLY_DATA_SIZE = 256;
+ char replyData[REPLY_DATA_SIZE];
+ bool secure = true;
+ for (int k = 0; k < 10; ++k) {
+ Parcel data;
+ data.writeInterfaceToken(effect->getInterfaceDescriptor());
+ data.writeInt32(0); // 0 is EFFECT_CMD_INIT
+ data.writeInt32(sizeof(cmdData));
+ data.write(cmdData, sizeof(cmdData));
+ data.writeInt32(sizeof(replyData));
+
+ Parcel reply;
+ status_t status = effect->asBinder()->transact(3, data, &reply); // 3 is COMMAND
+ ALOGV("transact status: %d", status);
+ if (status != NO_ERROR) {
+ ALOGW("invalid transaction status %d", status);
+ continue;
+ }
+
+ ALOGV("reply data avail %zu", reply.dataAvail());
+ status = reply.readInt32();
+ ALOGV("reply status %d", status);
+ if (status == NO_ERROR) {
+ continue;
+ }
+
+ int size = reply.readInt32();
+ ALOGV("reply size %d", size);
+ if (size != sizeof(replyData)) { // we expect 0 or full reply data if command failed
+ ALOGW_IF(size != 0, "invalid reply size: %d", size);
+ continue;
+ }
+
+ // Note that if reply.read() returns success, it should completely fill replyData.
+ status = reply.read(replyData, sizeof(replyData));
+ if (status != NO_ERROR) {
+ ALOGW("invalid reply read - ignoring");
+ continue;
+ }
+ unsigned int *out = (unsigned int *)replyData;
+ for (size_t index = 0; index < sizeof(replyData) / sizeof(*out); ++index) {
+ if (out[index] != 0) {
+ secure = false;
+ ALOGI("leaked data = %#08x", out[index]);
+ }
+ }
+ }
+ ALOGI("secure: %s", secure ? "YES" : "NO");
+ return secure;
+}
+
+static jboolean android_security_cts_AudioEffect_test_isCommandSecure()
+{
+ const sp<IAudioFlinger> &audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger.get() == NULL) {
+ ALOGE("could not get audioflinger");
+ return JNI_FALSE;
+ }
+
+ static const effect_uuid_t EFFECT_UIID_EQUALIZER = // type
+ { 0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }};
+ sp<EffectClient> effectClient(new EffectClient());
+ effect_descriptor_t descriptor;
+ memset(&descriptor, 0, sizeof(descriptor));
+ descriptor.type = EFFECT_UIID_EQUALIZER;
+ descriptor.uuid = *EFFECT_UUID_NULL;
+ const int32_t priority = 0;
+ const int sessionId = AUDIO_SESSION_OUTPUT_MIX;
+ const audio_io_handle_t io = 0; // AUDIO_IO_HANDLE_NONE
+ status_t status;
+ int32_t id;
+ int enabled;
+ sp<IEffect> effect = audioFlinger->createEffect(&descriptor, effectClient,
+ priority, io, sessionId, &status, &id, &enabled);
+ if (effect.get() == NULL || status != NO_ERROR) {
+ ALOGW("could not create effect");
+ return JNI_TRUE;
+ }
+
+ sp<DeathRecipient> deathRecipient(new DeathRecipient());
+ effect->asBinder()->linkToDeath(deathRecipient);
+
+ // check exploit
+ if (!isIEffectCommandSecure(effect.get())) {
+ ALOGE("not secure!");
+ return JNI_FALSE;
+ }
+
+ sleep(1); // wait to check death
+ if (deathRecipient->died()) {
+ ALOGE("effect binder died");
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+int register_android_security_cts_AudioEffectBinderTest(JNIEnv *env)
+{
+ static JNINativeMethod methods[] = {
+ { "native_test_isCommandSecure", "()Z",
+ (void *) android_security_cts_AudioEffect_test_isCommandSecure },
+ };
+
+ jclass clazz = env->FindClass("android/security/cts/AudioEffectBinderTest");
+ return env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0]));
+}
diff --git a/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
new file mode 100644
index 0000000..61b27f1
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_AudioFlingerBinderTest.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2015 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 LOG_TAG "AudioFlingerBinderTest-JNI"
+
+#include <jni.h>
+#include <binder/IServiceManager.h>
+#include <media/IAudioFlinger.h>
+#include <media/AudioSystem.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+using namespace android;
+
+/*
+ * Native methods used by
+ * cts/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
+ */
+
+#define TEST_ARRAY_SIZE 10000
+#define MAX_ARRAY_SIZE 1024
+#define TEST_PATTERN 0x55
+
+class MyDeathClient: public IBinder::DeathRecipient
+{
+public:
+ MyDeathClient() :
+ mAfIsDead(false) {
+ }
+
+ bool afIsDead() const { return mAfIsDead; }
+
+ // DeathRecipient
+ virtual void binderDied(const wp<IBinder>& who __unused) { mAfIsDead = true; }
+
+private:
+ bool mAfIsDead;
+};
+
+
+static bool connectAudioFlinger(sp<IAudioFlinger>& af, sp<MyDeathClient> &dr)
+{
+ int64_t startTime = 0;
+ while (af == 0) {
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16("media.audio_flinger"));
+ if (binder == 0) {
+ if (startTime == 0) {
+ startTime = uptimeMillis();
+ } else if ((uptimeMillis()-startTime) > 10000) {
+ ALOGE("timeout while getting audio flinger service");
+ return false;
+ }
+ sleep(1);
+ } else {
+ af = interface_cast<IAudioFlinger>(binder);
+ dr = new MyDeathClient();
+ binder->linkToDeath(dr);
+ }
+ }
+ return true;
+}
+
+/*
+ * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
+ * is opened.
+ */
+jboolean android_security_cts_AudioFlinger_test_setMasterMute(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ // force opening of a duplicating output
+ status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "0");
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ bool mute;
+ status = AudioSystem::getMasterMute(&mute);
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ AudioSystem::setMasterMute(!mute);
+
+ sleep(1);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ AudioSystem::setMasterMute(mute);
+
+ AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "0");
+
+ AudioSystem::setMasterMute(false);
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_setMasterVolume(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ // force opening of a duplicating output
+ status_t status = AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "0");
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ float vol;
+ status = AudioSystem::getMasterVolume(&vol);
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ AudioSystem::setMasterVolume(vol < 0.5 ? 1.0 : 0.0);
+
+ sleep(1);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ AudioSystem::setMasterMute(vol);
+
+ AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "0");
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_listAudioPorts(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ unsigned int num_ports = TEST_ARRAY_SIZE;
+ struct audio_port *ports =
+ (struct audio_port *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_port));
+
+ memset(ports, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_port));
+
+ status_t status = af->listAudioPorts(&num_ports, ports);
+
+ sleep(1);
+
+ // Check that the memory content above the max allowed array size was not changed
+ char *ptr = (char *)(ports + MAX_ARRAY_SIZE);
+ for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
+ if (ptr[i * sizeof(struct audio_port)] != TEST_PATTERN) {
+ free(ports);
+ return false;
+ }
+ }
+
+ free(ports);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_listAudioPatches(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ unsigned int num_patches = TEST_ARRAY_SIZE;
+ struct audio_patch *patches =
+ (struct audio_patch *)calloc(TEST_ARRAY_SIZE, sizeof(struct audio_patch));
+
+ memset(patches, TEST_PATTERN, TEST_ARRAY_SIZE * sizeof(struct audio_patch));
+
+ status_t status = af->listAudioPatches(&num_patches, patches);
+
+ sleep(1);
+
+ // Check that the memory content above the max allowed array size was not changed
+ char *ptr = (char *)(patches + MAX_ARRAY_SIZE);
+ for (size_t i = 0; i < TEST_ARRAY_SIZE - MAX_ARRAY_SIZE; i++) {
+ if (ptr[i * sizeof(struct audio_patch)] != TEST_PATTERN) {
+ free(patches);
+ return false;
+ }
+ }
+
+ free(patches);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ return true;
+}
+
+jboolean android_security_cts_AudioFlinger_test_createEffect(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioFlinger> af;
+ sp<MyDeathClient> dr;
+
+ if (!connectAudioFlinger(af, dr)) {
+ return false;
+ }
+
+ for (int j = 0; j < 10; ++j) {
+ Parcel data, reply;
+ data.writeInterfaceToken(af->getInterfaceDescriptor());
+ data.writeInt32((int32_t)j);
+ status_t status = af->asBinder()->transact(40, data, &reply); // 40 is CREATE_EFFECT
+ if (status != NO_ERROR) {
+ return false;
+ }
+
+ status = (status_t)reply.readInt32();
+ if (status == NO_ERROR) {
+ continue;
+ }
+
+ int id = reply.readInt32();
+ int enabled = reply.readInt32();
+ sp<IEffect> effect = interface_cast<IEffect>(reply.readStrongBinder());
+ effect_descriptor_t desc;
+ effect_descriptor_t descTarget;
+ memset(&desc, 0, sizeof(effect_descriptor_t));
+ memset(&descTarget, 0, sizeof(effect_descriptor_t));
+ reply.read(&desc, sizeof(effect_descriptor_t));
+ if (id != 0 || enabled != 0 || memcmp(&desc, &descTarget, sizeof(effect_descriptor_t))) {
+ return false;
+ }
+ }
+
+ sleep(1);
+
+ // Check that mediaserver did not crash
+ if (dr->afIsDead()) {
+ return false;
+ }
+
+ return true;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "native_test_setMasterMute", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_setMasterMute },
+ { "native_test_setMasterVolume", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_setMasterVolume },
+ { "native_test_listAudioPorts", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_listAudioPorts },
+ { "native_test_listAudioPatches", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_listAudioPatches },
+ { "native_test_createEffect", "()Z",
+ (void *) android_security_cts_AudioFlinger_test_createEffect },
+};
+
+int register_android_security_cts_AudioFlingerBinderTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/security/cts/AudioFlingerBinderTest");
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
index 6807523..71d9948 100644
--- a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
@@ -18,6 +18,7 @@
#include <jni.h>
#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <media/IAudioPolicyService.h>
#include <media/AudioSystem.h>
#include <system/audio.h>
@@ -151,12 +152,12 @@
return false;
}
- status_t status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
- if (status == NO_ERROR) {
+ bool status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
+ if (status) {
return false;
}
status = aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0);
- if (status == NO_ERROR) {
+ if (status) {
return false;
}
return true;
@@ -186,6 +187,64 @@
return true;
}
+jboolean android_security_cts_AudioPolicy_test_startAudioSource(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioPolicyService> aps;
+
+ if (!init(aps, NULL, NULL)) {
+ return false;
+ }
+
+ // Keep synchronized with IAudioPolicyService.cpp!
+ enum {
+ START_AUDIO_SOURCE = 41,
+ };
+
+ for (int i = 0; i < 10; ++i) {
+ Parcel data, reply;
+ data.writeInterfaceToken(aps->getInterfaceDescriptor());
+ data.writeInt32(-i);
+ aps->asBinder()->transact(START_AUDIO_SOURCE, data, &reply);
+ status_t err = (status_t)reply.readInt32();
+ if (err == NO_ERROR) {
+ continue;
+ }
+ audio_io_handle_t handle = (audio_io_handle_t)reply.readInt32();
+ if (handle != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+jint android_security_cts_AudioPolicy_test_getStreamVolumeLeak(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ sp<IAudioPolicyService> aps;
+
+ if (!init(aps, NULL, NULL)) {
+ return -1;
+ }
+
+ // Keep synchronized with IAudioPolicyService.cpp!
+ enum {
+ GET_STREAM_VOLUME = 17,
+ };
+
+ Parcel data, reply;
+ status_t err;
+ data.writeInterfaceToken(aps->getInterfaceDescriptor());
+ data.writeInt32(-1); // stream type
+ data.writeInt32(-1); // device
+ aps->asBinder()->transact(GET_STREAM_VOLUME, data, &reply);
+ int index = reply.readInt32();
+ err = reply.readInt32();
+
+ return index;
+}
+
static JNINativeMethod gMethods[] = {
{ "native_test_startOutput", "()Z",
(void *) android_security_cts_AudioPolicy_test_startOutput },
@@ -195,6 +254,10 @@
(void *) android_security_cts_AudioPolicy_test_isStreamActive },
{ "native_test_isStreamActiveRemotely", "()Z",
(void *) android_security_cts_AudioPolicy_test_isStreamActiveRemotely },
+ { "native_test_startAudioSource", "()Z",
+ (void *) android_security_cts_AudioPolicy_test_startAudioSource },
+ { "native_test_getStreamVolumeLeak", "()I",
+ (void *) android_security_cts_AudioPolicy_test_getStreamVolumeLeak },
};
int register_android_security_cts_AudioPolicyBinderTest(JNIEnv* env)
diff --git a/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
new file mode 100644
index 0000000..41262ac
--- /dev/null
+++ b/tests/tests/security/jni/android_security_cts_MediaPlayerInfoLeakTest.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 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 LOG_TAG "MediaPlayerInfoLeakTest-JNI"
+
+#include <jni.h>
+
+#include <binder/Parcel.h>
+#include <binder/IServiceManager.h>
+
+#include <media/IMediaPlayer.h>
+#include <media/IMediaPlayerService.h>
+#include <media/IMediaPlayerClient.h>
+
+#include <sys/stat.h>
+
+using namespace android;
+
+static status_t connectMediaPlayer(sp<IMediaPlayer>& iMP)
+{
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> mediaPlayerService = sm->checkService(String16("media.player"));
+
+ sp<IMediaPlayerService> iMPService = IMediaPlayerService::asInterface(mediaPlayerService);
+ sp<IMediaPlayerClient> client;
+ Parcel data, reply;
+ int dummyAudioSessionId = 1;
+ data.writeInterfaceToken(iMPService->getInterfaceDescriptor());
+ data.writeStrongBinder(client->asBinder());
+ data.writeInt32(dummyAudioSessionId);
+
+ // Keep synchronized with IMediaPlayerService.cpp!
+ enum {
+ CREATE = IBinder::FIRST_CALL_TRANSACTION,
+ };
+ status_t err = iMPService->asBinder()->transact(CREATE, data, &reply);
+
+ if (err == NO_ERROR) {
+ iMP = interface_cast<IMediaPlayer>(reply.readStrongBinder());
+ }
+ return err;
+}
+
+int testMediaPlayerInfoLeak(int command)
+{
+ sp<IMediaPlayer> iMP;
+ if (NO_ERROR != connectMediaPlayer(iMP)) {
+ return false;
+ }
+
+
+ Parcel data, reply;
+ data.writeInterfaceToken(iMP->getInterfaceDescriptor());
+ iMP->asBinder()->transact(command, data, &reply);
+
+ int leak = reply.readInt32();
+ status_t err = reply.readInt32();
+ return leak;
+}
+
+jint android_security_cts_MediaPlayer_test_getCurrentPositionLeak(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ // Keep synchronized with IMediaPlayer.cpp!
+ enum {
+ GET_CURRENT_POSITION = 11,
+ };
+ return testMediaPlayerInfoLeak(GET_CURRENT_POSITION);
+}
+
+jint android_security_cts_MediaPlayer_test_getDurationLeak(JNIEnv* env __unused,
+ jobject thiz __unused)
+{
+ // Keep synchronized with IMediaPlayer.cpp!
+ enum {
+ GET_DURATION = 12,
+ };
+ return testMediaPlayerInfoLeak(GET_DURATION);
+}
+
+static JNINativeMethod gMethods[] = {
+ { "native_test_getCurrentPositionLeak", "()I",
+ (void *) android_security_cts_MediaPlayer_test_getCurrentPositionLeak },
+ { "native_test_getDurationLeak", "()I",
+ (void *) android_security_cts_MediaPlayer_test_getDurationLeak },
+};
+
+int register_android_security_cts_MediaPlayerInfoLeakTest(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/security/cts/MediaPlayerInfoLeakTest");
+ return env->RegisterNatives(clazz, gMethods,
+ sizeof(gMethods) / sizeof(JNINativeMethod));
+}
diff --git a/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java b/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
new file mode 100644
index 0000000..20d9615
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AudioEffectBinderTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 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 android.media.audiofx.AudioEffect;
+
+import java.util.UUID;
+
+import junit.framework.TestCase;
+
+public class AudioEffectBinderTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+ /**
+ * Checks that IEffect::command() cannot leak data.
+ */
+ public void test_isCommandSecure() throws Exception {
+ if (isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
+ assertTrue(native_test_isCommandSecure());
+ }
+ }
+
+ /* see AudioEffect.isEffectTypeAvailable(), implements hidden function */
+ private static boolean isEffectTypeAvailable(UUID type) {
+ AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
+ if (desc == null) {
+ return false;
+ }
+
+ for (int i = 0; i < desc.length; i++) {
+ if (desc[i].type.equals(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static native boolean native_test_isCommandSecure();
+}
diff --git a/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
new file mode 100644
index 0000000..202bd65
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AudioFlingerBinderTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 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 junit.framework.TestCase;
+
+public class AudioFlingerBinderTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+ /**
+ * Checks that AudioSystem::setMasterMute() does not crash mediaserver if a duplicated output
+ * is opened.
+ */
+ public void test_setMasterMute() throws Exception {
+ assertTrue(native_test_setMasterMute());
+ }
+
+ /**
+ * Checks that AudioSystem::setMasterVolume() does not crash mediaserver if a duplicated output
+ * is opened.
+ */
+ public void test_setMasterVolume() throws Exception {
+ assertTrue(native_test_setMasterVolume());
+ }
+
+ /**
+ * Checks that IAudioFlinger::listAudioPorts() does not cause a memory overflow when passed a
+ * large number of ports.
+ */
+ public void test_listAudioPorts() throws Exception {
+ assertTrue(native_test_listAudioPorts());
+ }
+
+ /**
+ * Checks that IAudioFlinger::listAudioPatches() does not cause a memory overflow when passed a
+ * large number of ports.
+ */
+ public void test_listAudioPatches() throws Exception {
+ assertTrue(native_test_listAudioPatches());
+ }
+
+ /**
+ * Checks that IAudioFlinger::createEffect() does not leak information on the server side.
+ */
+ public void test_createEffect() throws Exception {
+ assertTrue(native_test_createEffect());
+ }
+
+ private static native boolean native_test_setMasterMute();
+ private static native boolean native_test_setMasterVolume();
+ private static native boolean native_test_listAudioPorts();
+ private static native boolean native_test_listAudioPatches();
+ private static native boolean native_test_createEffect();
+}
diff --git a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
index b307247..615dbf3 100644
--- a/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
+++ b/tests/tests/security/src/android/security/cts/AudioPolicyBinderTest.java
@@ -56,8 +56,27 @@
assertTrue(native_test_isStreamActiveRemotely());
}
+ /**
+ * Checks that IAudioPolicyService::startAudioSource() cannot leak information from
+ * server side.
+ */
+ public void test_startAudioSource() throws Exception {
+ assertTrue(native_test_startAudioSource());
+ }
+
+ /**
+ * Checks that IAudioPolicyService::getStreamVolumeIndex() does not leak information
+ * when called with an invalid stream/device type.
+ */
+ public void test_getStreamVolumeLeak() throws Exception {
+ int volume = native_test_getStreamVolumeLeak();
+ assertTrue(String.format("Leaked volume 0x%08X", volume), volume == 0);
+ }
+
private static native boolean native_test_startOutput();
private static native boolean native_test_stopOutput();
private static native boolean native_test_isStreamActive();
private static native boolean native_test_isStreamActiveRemotely();
+ private static native boolean native_test_startAudioSource();
+ private static native int native_test_getStreamVolumeLeak();
}
diff --git a/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
new file mode 100644
index 0000000..e34fc05
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaPlayerInfoLeakTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 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 junit.framework.TestCase;
+
+public class MediaPlayerInfoLeakTest extends TestCase {
+
+ static {
+ System.loadLibrary("ctssecurity_jni");
+ }
+
+
+ /**
+ * Checks that IMediaPlayer::getCurrentPosition() does not leak info in error case
+ */
+ public void test_getCurrentPositionLeak() throws Exception {
+ int pos = native_test_getCurrentPositionLeak();
+ assertTrue(String.format("Leaked pos 0x%08X", pos), pos == 0);
+ }
+
+ /**
+ * Checks that IMediaPlayer::getDuration() does not leak info in error case
+ */
+ public void test_getDurationLeak() throws Exception {
+ int dur = native_test_getDurationLeak();
+ assertTrue(String.format("Leaked dur 0x%08X", dur), dur == 0);
+ }
+
+ private static native int native_test_getCurrentPositionLeak();
+ private static native int native_test_getDurationLeak();
+}
diff --git a/tests/tests/security/src/android/security/cts/PutOverflowTest.java b/tests/tests/security/src/android/security/cts/PutOverflowTest.java
new file mode 100644
index 0000000..e0eb34c
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/PutOverflowTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 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 android.test.AndroidTestCase;
+import java.lang.reflect.Method;
+
+public class PutOverflowTest extends AndroidTestCase {
+ public void testCrash() throws Exception {
+ try {
+ Class<?> keystoreClass = Class.forName("android.security.KeyStore");
+ Method getInstance = keystoreClass.getMethod("getInstance");
+ Method put = keystoreClass.getMethod("put",
+ String.class, byte[].class, int.class, int.class);
+ Object keystore = getInstance.invoke(null);
+ byte[] buffer = new byte[65536];
+ Boolean result = (Boolean)put.invoke(keystore, "crashFile", buffer, -1, 0);
+ assertTrue("Fix for ANDROID-22802399 not present", result);
+ } catch (ReflectiveOperationException ignored) {
+ // Since this test requires reflection avoid causing undue failures if classes or
+ // methods were changed.
+ }
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
index bda0d6d..00cbfd8 100644
--- a/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
+++ b/tests/tests/security/src/android/security/cts/ServicePermissionsTest.java
@@ -137,9 +137,7 @@
if (lines.size() == 1) {
String message = lines.get(0);
- if ("backup".equals(service) && "Inactive".equals(message)) {
- Log.i(TAG, "Exempt inactive backup service.");
- } else if (!message.contains("Permission Denial") &&
+ if (!message.contains("Permission Denial") &&
!message.contains("android.permission.DUMP")) {
fail("dump() for " + service + " produced a single line which didn't "
+ "reference a permission; it may be leaking sensitive data.");
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 2be1dcb..b6ae8ec 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -186,7 +186,10 @@
break;
case TelephonyManager.PHONE_TYPE_NONE:
- if (mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI) != null) {
+ boolean nwSupported = mCm.isNetworkSupported(mCm.TYPE_WIFI);
+ PackageManager packageManager = getContext().getPackageManager();
+ // only check serial number & MAC address if device report wifi feature
+ if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
assertSerialNumber();
assertMacAddress(getWifiMacAddress());
} else if (mCm.getNetworkInfo(ConnectivityManager.TYPE_BLUETOOTH) != null) {
diff --git a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
index 10d08d0..482edb0 100644
--- a/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ArrowKeyMovementMethodTest.java
@@ -255,7 +255,7 @@
assertFalse(mArrowKeyMovementMethod.onKeyDown(mTextView, mEditable,
KeyEvent.KEYCODE_DPAD_UP, noMetaEvent));
- // |first line
+ // first lin|e
// second line
// last line
assertSelection(0);
diff --git a/tests/tests/uirendering/res/layout/simple_shadow_layout.xml b/tests/tests/uirendering/res/layout/simple_shadow_layout.xml
index 2f21df0..f97974b 100644
--- a/tests/tests/uirendering/res/layout/simple_shadow_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_shadow_layout.xml
@@ -23,4 +23,4 @@
android:translationY="25px"
android:elevation="10dp"
android:background="#fff" />
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/tools/device-setup/TestDeviceSetup/Android.mk b/tools/device-setup/TestDeviceSetup/Android.mk
index 7238117..44e66bb 100644
--- a/tools/device-setup/TestDeviceSetup/Android.mk
+++ b/tools/device-setup/TestDeviceSetup/Android.mk
@@ -25,8 +25,7 @@
LOCAL_DEX_PREOPT := false
LOCAL_PROGUARD_ENABLED := disabled
-# uncomment when b/13282254 is fixed
-#LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := TestDeviceSetup
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
index 4ba1160..8fb61bf 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
@@ -50,8 +50,6 @@
public static final String RESOLUTION = "resolution";
public static final String VERSION_SDK = "androidPlatformVersion";
public static final String VERSION_RELEASE = "buildVersion";
- public static final String VERSION_BASE_OS = "base_os";
- public static final String VERSION_SECURITY_PATCH = "security_patch";
public static final String BUILD_ABI = "build_abi";
public static final String BUILD_ABI2 = "build_abi2";
public static final String BUILD_ABIS = "build_abis";
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
index 42ba066..5828259 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
@@ -27,7 +27,6 @@
import android.os.Bundle;
import android.os.Environment;
import android.os.UserManager;
-import android.os.SystemProperties;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
@@ -81,9 +80,6 @@
addResult(VERSION_RELEASE, Build.VERSION.RELEASE);
addResult(VERSION_SDK, Build.VERSION.SDK);
- addResult(VERSION_BASE_OS, SystemProperties.get("ro.build.version.base_os", ""));
- addResult(VERSION_SECURITY_PATCH,
- SystemProperties.get("ro.build.version.security_patch", ""));
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getContext().getSystemService(