Merge "Verify onNewIntent lifecycle" into pi-dev
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index ada8384..ffdb72f 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -98,6 +98,7 @@
pre-installed-apps := \
CtsEmptyDeviceAdmin \
+ CtsEmptyDeviceOwner \
CtsPermissionApp \
NotificationBot
@@ -120,7 +121,7 @@
cts-verifier: CtsVerifier adb $(pre-installed-apps)
adb install -r $(PRODUCT_OUT)/data/app/CtsVerifier/CtsVerifier.apk \
$(foreach app,$(pre-installed-apps), \
- && adb install -r $(call apk-location-for,$(app))) \
+ && adb install -r -t $(call apk-location-for,$(app))) \
&& adb shell "am start -n com.android.cts.verifier/.CtsVerifierActivity"
#
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 2b80d20..6816429 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2649,8 +2649,9 @@
<string name="set_device_owner_button_label">Set up device owner</string>
<string name="set_device_owner_dialog_title">Set up device owner</string>
<string name="set_device_owner_dialog_text">
+ This test requires CtsEmptyDeviceOwner.apk to be installed on the device.
Please set the device owner by enabling USB debugging on the device and issuing the following command on the host:\n
- adb shell dpm set-device-owner \'com.android.cts.verifier/com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver\'
+ adb shell dpm set-device-owner com.android.cts.emptydeviceowner/.EmptyDeviceAdmin
</string>
<string name="device_owner_remove_device_owner_test">Remove device owner</string>
<string name="device_owner_remove_device_owner_test_info">
diff --git a/apps/CtsVerifier/res/xml/device_admin_byod.xml b/apps/CtsVerifier/res/xml/device_admin_byod.xml
index b1ba372..2d33459 100644
--- a/apps/CtsVerifier/res/xml/device_admin_byod.xml
+++ b/apps/CtsVerifier/res/xml/device_admin_byod.xml
@@ -16,6 +16,7 @@
<!-- BEGIN_INCLUDE(meta_data) -->
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+ <support-transfer-ownership/>
<uses-policies>
<limit-password />
<watch-login />
diff --git a/apps/EmptyDeviceOwner/Android.mk b/apps/EmptyDeviceOwner/Android.mk
new file mode 100644
index 0000000..714e996
--- /dev/null
+++ b/apps/EmptyDeviceOwner/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsEmptyDeviceOwner
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/res
+
+LOCAL_SDK_VERSION := current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/apps/EmptyDeviceOwner/AndroidManifest.xml b/apps/EmptyDeviceOwner/AndroidManifest.xml
new file mode 100644
index 0000000..d6a97eb
--- /dev/null
+++ b/apps/EmptyDeviceOwner/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.emptydeviceowner" >
+
+ <uses-sdk android:minSdkVersion="12"/>
+
+ <application android:label="Test Device Owner" android:testOnly="true">
+ <receiver
+ android:name=".EmptyDeviceAdmin"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data
+ android:name="android.app.device_admin"
+ android:resource="@xml/device_admin"/>
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
+ <receiver android:name=".DeviceOwnerChangedReceiver">
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_OWNER_CHANGED"/>
+ </intent-filter>
+ </receiver>
+
+ </application>
+</manifest>
diff --git a/apps/EmptyDeviceOwner/README b/apps/EmptyDeviceOwner/README
new file mode 100644
index 0000000..5bcba3b
--- /dev/null
+++ b/apps/EmptyDeviceOwner/README
@@ -0,0 +1,20 @@
+Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache Licence, 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.
+
+This package is used to generate CtsEmptyDeviceOwner.apk that is used in assets of CtsVerifier.
+To update the apk file, run the following commands from your android checkout:
+cd $ANDROID_BUILD_TOP
+make -j32 CtsEmptyDeviceOwner
+cp $OUT/data/app/CtsEmptyDeviceOwner/CtsEmptyDeviceOwner.apk \
+cts/apps/CtsVerifier/assets/apk/CtsEmptyDeviceOwner.apk
diff --git a/apps/EmptyDeviceOwner/res/xml/device_admin.xml b/apps/EmptyDeviceOwner/res/xml/device_admin.xml
new file mode 100644
index 0000000..0cff9e5
--- /dev/null
+++ b/apps/EmptyDeviceOwner/res/xml/device_admin.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-policies>
+ <limit-password />
+ <watch-login />
+ <reset-password />
+ <force-lock />
+ <wipe-data />
+ <expire-password />
+ <encrypted-storage />
+ <disable-camera />
+ <disable-keyguard-features />
+ </uses-policies>
+</device-admin>
diff --git a/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/DeviceOwnerChangedReceiver.java b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/DeviceOwnerChangedReceiver.java
new file mode 100644
index 0000000..8f0732e
--- /dev/null
+++ b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/DeviceOwnerChangedReceiver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.emptydeviceowner;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class DeviceOwnerChangedReceiver extends DeviceAdminReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d("DeviceOwnerChangedReceiver", "device owner is changed.");
+ if (!DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED.equals(intent.getAction())) {
+ return;
+ }
+ DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
+ if (!dpm.isDeviceOwnerApp(context.getPackageName())) {
+ return;
+ }
+ Log.d("DeviceOwnerChangedReceiver", "transferring ownership to CtsVerifier");
+ dpm.transferOwnership(
+ EmptyDeviceAdmin.getComponentName(context),
+ new ComponentName("com.android.cts.verifier",
+ "com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver"),
+ null);
+ }
+}
diff --git a/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/EmptyDeviceAdmin.java b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/EmptyDeviceAdmin.java
new file mode 100644
index 0000000..90ee252
--- /dev/null
+++ b/apps/EmptyDeviceOwner/src/com/android/cts/emptydeviceowner/EmptyDeviceAdmin.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.emptydeviceowner;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class EmptyDeviceAdmin extends DeviceAdminReceiver {
+
+ public static ComponentName getComponentName(Context context) {
+ return new ComponentName(context, EmptyDeviceAdmin.class);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetSystemSettingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetSystemSettingTest.java
new file mode 100644
index 0000000..0fbbee1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/SetSystemSettingTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.deviceandprofileowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+/**
+ * Test {@link DevicePolicyManager#setSystemSetting}.
+ */
+public class SetSystemSettingTest extends BaseDeviceAdminTest {
+
+ private static final String TEST_BRIGHTNESS_1 = "200";
+ private static final String TEST_BRIGHTNESS_2 = "100";
+
+ private void testSetBrightnessWithValue(String testBrightness) {
+ mDevicePolicyManager.setSystemSetting(ADMIN_RECEIVER_COMPONENT,
+ Settings.System.SCREEN_BRIGHTNESS, testBrightness);
+ assertEquals(testBrightness, Settings.System.getStringForUser(
+ mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
+ UserHandle.myUserId()));
+ }
+
+ public void testSetBrightness() {
+ testSetBrightnessWithValue(TEST_BRIGHTNESS_1);
+ testSetBrightnessWithValue(TEST_BRIGHTNESS_2);
+ }
+
+ public void testSetSystemSettingsFailsForNonWhitelistedSettings() throws Exception {
+ try {
+ mDevicePolicyManager.setSystemSetting(ADMIN_RECEIVER_COMPONENT,
+ Settings.System.TEXT_AUTO_REPLACE, "0");
+ fail("Didn't throw security exception.");
+ } catch (SecurityException e) {
+ // Should throw SecurityException.
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetSystemSettingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetSystemSettingTest.java
deleted file mode 100644
index 06e6149..0000000
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/SetSystemSettingTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.cts.deviceowner;
-
-import android.app.admin.DevicePolicyManager;
-import android.provider.Settings;
-
-/**
- * Test {@link DevicePolicyManager#setSystemSetting}.
- */
-public class SetSystemSettingTest extends BaseDeviceOwnerTest {
-
- private static final String TEST_BRIGHTNESS_1 = "200";
- private static final String TEST_BRIGHTNESS_2 = "100";
-
- private void testSetBrightnessWithValue(String testBrightness) {
- mDevicePolicyManager.setSystemSetting(getWho(),
- Settings.System.SCREEN_BRIGHTNESS, testBrightness);
- assertEquals(testBrightness, Settings.System.getString(mContext.getContentResolver(),
- Settings.System.SCREEN_BRIGHTNESS));
- }
-
- public void testSetBrightness() {
- testSetBrightnessWithValue(TEST_BRIGHTNESS_1);
- testSetBrightnessWithValue(TEST_BRIGHTNESS_2);
- }
-
- public void testSetSystemSettingsFailsForNonWhitelistedSettings() throws Exception {
- try {
- mDevicePolicyManager.setSystemSetting(getWho(),
- Settings.System.TEXT_AUTO_REPLACE, "0");
- fail("Didn't throw security exception.");
- } catch (SecurityException e) {
- // Should throw SecurityException.
- }
- }
-}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 274edab..a2dae8a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -851,6 +851,13 @@
executeDeviceTestClass(".PasswordSufficientInitiallyTest");
}
+ public void testSetSystemSetting() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ executeDeviceTestClass(".SetSystemSettingTest");
+ }
+
protected void executeResetPasswordWithTokenTests(Boolean allowFailures) throws Exception {
runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".ResetPasswordWithTokenTest", null, mUserId,
Collections.singletonMap(ARG_ALLOW_FAILURE, Boolean.toString(allowFailures)));
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 47e46a5..0233d4e 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -948,13 +948,6 @@
executeDeviceOwnerTest("AirplaneModeRestrictionTest");
}
- public void testSetSystemSetting() throws Exception {
- if (!mHasFeature) {
- return;
- }
- executeDeviceOwnerTest("SetSystemSettingTest");
- }
-
public void testOverrideApn() throws Exception {
if (!mHasFeature) {
return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 6cedba5..b39e1ad 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -165,4 +165,9 @@
// MixedProfileOwnerTest
executeResetPasswordWithTokenTests(false);
}
+
+ @Override
+ public void testSetSystemSetting() {
+ // Managed profile owner cannot set currently whitelisted system settings.
+ }
}
diff --git a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
index 2b9e5a6..65fd3ff 100644
--- a/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
+++ b/hostsidetests/incident/apps/graphicsstatsapp/src/com/android/server/cts/device/graphicsstats/DrawFramesActivity.java
@@ -114,7 +114,7 @@
}
private void jank() {
- spinSleep(20);
+ spinSleep(24);
}
private void spinSleep(int durationMs) {
@@ -128,7 +128,7 @@
jankIf(FRAME_JANK_ANIMATION);
});
if (isFrameFlagSet(FRAME_JANK_MISS_VSYNC)) {
- spinSleep(32);
+ spinSleep(45);
}
}
@@ -161,7 +161,7 @@
long timeoutDurationMs = 0;
for (int frame : framesToDraw) {
// 50ms base time + 20ms for every extra jank event
- timeoutDurationMs += 50 + (20 * Integer.bitCount(frame));
+ timeoutDurationMs += 50 + (24 * Integer.bitCount(frame));
if ((frame & FRAME_JANK_DAVEY_JR) != 0) {
timeoutDurationMs += 150;
}
diff --git a/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java
index 2a08eb7..35d1bb6 100644
--- a/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/AlarmManagerIncidentTest.java
@@ -45,8 +45,9 @@
// Times should be positive.
assertTrue(0 < dump.getCurrentTime());
assertTrue(0 < dump.getElapsedRealtime());
- assertTrue(0 < dump.getLastTimeChangeClockTime());
- assertTrue(0 < dump.getLastTimeChangeRealtime());
+ // Can be 0 if the time hasn't been changed yet.
+ assertTrue(0 <= dump.getLastTimeChangeClockTime());
+ assertTrue(0 <= dump.getLastTimeChangeRealtime());
// ConstantsProto
ConstantsProto settings = dump.getSettings();
diff --git a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
index 3977c74..398d511 100644
--- a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
@@ -170,9 +170,6 @@
assertNotNull(jssi);
assertTrue(0 <= jssi.getCallingUid());
- if (filterLevel == PRIVACY_AUTO) {
- assertTrue(jssi.getBatteryName().isEmpty());
- }
}
private static void testJobStatusDumpProto(JobStatusDumpProto jsd) throws Exception {
diff --git a/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java b/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
index 4acf5ba..1788c80 100644
--- a/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
+++ b/hostsidetests/incident/src/com/android/server/cts/ProtoDumpTestCase.java
@@ -53,6 +53,20 @@
protected static final int PRIVACY_LOCAL = 2;
/** No privacy filtering has been done. All fields should be present. */
protected static final int PRIVACY_NONE = 3;
+ protected static String privacyToString(int privacy) {
+ switch (privacy) {
+ case PRIVACY_AUTO:
+ return "AUTO";
+ case PRIVACY_EXPLICIT:
+ return "EXPLICIT";
+ case PRIVACY_LOCAL:
+ return "LOCAL";
+ case PRIVACY_NONE:
+ return "NONE";
+ default:
+ return "UNKNOWN";
+ }
+ }
protected IBuildInfo mCtsBuild;
diff --git a/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java
index 052e3dd..dc14384 100644
--- a/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/SettingsIncidentTest.java
@@ -22,14 +22,20 @@
import android.providers.settings.UserSettingsProto;
import com.android.ddmlib.Log.LogLevel;
+import com.android.incident.Destination;
+import com.android.incident.Privacy;
import com.android.tradefed.log.LogUtil.CLog;
import com.google.protobuf.GeneratedMessage;
+import com.google.protobuf.Descriptors.FieldDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -58,52 +64,64 @@
assertEquals(0, userSettings.getUserId());
CLog.logAndDisplay(LogLevel.INFO, "#*#*#*#*#*#*#*#*#*#*# SECURE #*#*#*#*#*#*#*#*#*#*#");
- verifySettings(userSettings.getSecureSettings());
+ verifySettings(userSettings.getSecureSettings(), filterLevel);
CLog.logAndDisplay(LogLevel.INFO, "#*#*#*#*#*#*#*#*#*#*# SYSTEM #*#*#*#*#*#*#*#*#*#*#");
- verifySettings(userSettings.getSystemSettings());
+ verifySettings(userSettings.getSystemSettings(), filterLevel);
CLog.logAndDisplay(LogLevel.INFO, "#*#*#*#*#*#*#*#*#*#*# GLOBAL #*#*#*#*#*#*#*#*#*#*#");
- verifySettings(dump.getGlobalSettings());
+ verifySettings(dump.getGlobalSettings(), filterLevel);
}
- private static void verifySettings(GeneratedMessage settings) throws Exception {
- verifySettings(getSettingProtos(settings));
+ private static void verifySettings(GeneratedMessage settings, final int filterLevel) throws Exception {
+ verifySettings(getSettingProtos(settings), filterLevel);
final List<SettingsOperationProto> ops = invoke(settings, "getHistoricalOperationsList");
for (SettingsOperationProto op : ops) {
assertTrue(op.getTimestamp() >= 0);
assertNotNull(op.getOperation());
// setting is optional
+ if (filterLevel == PRIVACY_AUTO) {
+ // SettingOperationProto is EXPLICIT by default.
+ assertTrue(op.getOperation().isEmpty());
+ assertTrue(op.getSetting().isEmpty());
+ }
}
}
- private static List<SettingProto> getSettingProtos(GeneratedMessage settingsProto) {
+ private static Map<SettingProto, Destination> getSettingProtos(GeneratedMessage settingsProto) {
CLog.d("Checking out class: " + settingsProto.getClass());
- Stream<SettingProto> settings = Arrays.stream(settingsProto.getClass().getDeclaredMethods())
- .filter((method) ->
- method.getName().startsWith("get")
- && !method.getName().endsWith("OrBuilder")
- && method.getParameterCount() == 0
- && !Modifier.isStatic(method.getModifiers())
- && method.getReturnType() == SettingProto.class)
- .map((method) -> (SettingProto) invoke(method, settingsProto));
+ Map<SettingProto, Destination> settings = new HashMap<>();
+ for (FieldDescriptor fd : settingsProto.getDescriptorForType().getFields()) {
+ if (fd.getType() != FieldDescriptor.Type.MESSAGE) {
+ // Only looking for SettingProtos and messages that contain them. Skip any primitive
+ // fields.
+ continue;
+ }
+ List<Object> tmp;
+ if (fd.isRepeated()) {
+ tmp = (List) settingsProto.getField(fd);
+ } else {
+ tmp = new ArrayList<>();
+ tmp.add(settingsProto.getField(fd));
+ }
+ Destination dest = fd.getOptions().getExtension(Privacy.privacy).getDest();
+ for (Object o : tmp) {
+ if ("android.providers.settings.SettingProto".equals(fd.getMessageType().getFullName())) {
+ // The container's default privacy doesn't affect message types. However,
+ // anotations on the field override the message's default annotation. If a
+ // message field doesn't have an annotation, it is treated as EXPLICIT by
+ // default.
+ settings.put((SettingProto) o, dest == Destination.DEST_UNSET ? Destination.DEST_EXPLICIT : dest);
+ } else {
+ // Sub messages don't inherit the container's default privacy. If the field had
+ // an annotation, it would override the sub message's default privacy.
+ settings.putAll(getSettingProtos((GeneratedMessage) o));
+ }
+ }
+ }
- // Get fields in the submessages.
- Stream<SettingProto> subSettings = Arrays.stream(settingsProto.getClass().getDeclaredMethods())
- .filter((method) ->
- method.getName().startsWith("get")
- && !method.getName().endsWith("OrBuilder")
- && method.getParameterCount() == 0
- && !Modifier.isStatic(method.getModifiers())
- && method.getReturnType() != SettingProto.class
- && GeneratedMessage.class.isAssignableFrom(method.getReturnType())
- && method.getReturnType() != settingsProto.getClass())
- .map((method) -> getSettingProtos((GeneratedMessage) invoke(method, settingsProto)))
- // getSettingsProtos returns List<>, so flatten all of them into one.
- .flatMap(Collection::stream);
-
- return Stream.concat(settings, subSettings).collect(Collectors.toList());
+ return settings;
}
private static <T> T invoke(Method method, Object instance, Object... args) {
@@ -129,11 +147,13 @@
return c == Integer.class ? int.class : c;
}
- private static void verifySettings(List<SettingProto> settings) throws Exception {
+ private static void verifySettings(Map<SettingProto, Destination> settings, final int filterLevel) throws Exception {
assertFalse(settings.isEmpty());
CLog.d("Field count: " + settings.size());
- for (SettingProto setting : settings) {
+ for (Map.Entry<SettingProto, Destination> sDPair : settings.entrySet()) {
+ SettingProto setting = sDPair.getKey();
+ Destination dest = sDPair.getValue();
try {
final String id = setting.getId();
if (!id.isEmpty()) {
@@ -141,6 +161,27 @@
Long.parseLong(id);
}
assertNotNull(setting.getName());
+ if (filterLevel < PRIVACY_LOCAL) {
+ if (dest == Destination.DEST_LOCAL) {
+ // Any filter that is not LOCAL should make sure local isn't printed at all.
+ String err = "Setting '" + setting.getName() + "' with LOCAL privacy didn't strip data for filter level '" + privacyToString(filterLevel) + "'";
+ assertTrue(err, setting.getId().isEmpty());
+ assertTrue(err, setting.getName().isEmpty());
+ assertTrue(err, setting.getPkg().isEmpty());
+ assertTrue(err, setting.getValue().isEmpty());
+ assertTrue(err, setting.getDefaultValue().isEmpty());
+ }
+ if (filterLevel < PRIVACY_EXPLICIT) {
+ if (dest == Destination.DEST_EXPLICIT) {
+ String err = "Setting '" + setting.getName() + "' with EXPLICIT privacy didn't strip data for filter level '" + privacyToString(filterLevel) + "'";
+ assertTrue(err, setting.getId().isEmpty());
+ assertTrue(err, setting.getName().isEmpty());
+ assertTrue(err, setting.getPkg().isEmpty());
+ assertTrue(err, setting.getValue().isEmpty());
+ assertTrue(err, setting.getDefaultValue().isEmpty());
+ }
+ }
+ }
// pkg is optional
// value can be anything
// default can be anything
diff --git a/hostsidetests/seccomp/app/Android.mk b/hostsidetests/seccomp/app/Android.mk
index 4dd5ad2..041d760 100644
--- a/hostsidetests/seccomp/app/Android.mk
+++ b/hostsidetests/seccomp/app/Android.mk
@@ -40,6 +40,8 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
+
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
diff --git a/hostsidetests/seccomp/app/assets/syscalls.json b/hostsidetests/seccomp/app/assets/syscalls.json
new file mode 100644
index 0000000..527405f
--- /dev/null
+++ b/hostsidetests/seccomp/app/assets/syscalls.json
@@ -0,0 +1,53 @@
+{
+ "arm": {
+ "add_key": 309,
+ "inotify_init": 316,
+ "keyctl": 311,
+ "openat": 322,
+ "swapoff": 115,
+ "swapon": 87,
+ "syncfs": 373
+ },
+ "arm64": {
+ "add_key": 217,
+ "keyctl": 219,
+ "openat": 56,
+ "swapoff": 225,
+ "swapon": 224,
+ "syncfs": 267
+ },
+ "mips": {
+ "add_key": 4280,
+ "inotify_init": 4284,
+ "keyctl": 4282,
+ "openat": 4288,
+ "swapoff": 4115,
+ "swapon": 4087,
+ "syncfs": 4342
+ },
+ "mips64": {
+ "add_key": 5239,
+ "keyctl": 5241,
+ "openat": 5247,
+ "swapoff": 5163,
+ "swapon": 5162,
+ "syncfs": 5301
+ },
+ "x86": {
+ "add_key": 286,
+ "inotify_init": 291,
+ "keyctl": 288,
+ "openat": 295,
+ "swapoff": 115,
+ "swapon": 87,
+ "syncfs": 344
+ },
+ "x86_64": {
+ "add_key": 248,
+ "keyctl": 250,
+ "openat": 257,
+ "swapoff": 168,
+ "swapon": 167,
+ "syncfs": 306
+ }
+}
diff --git a/hostsidetests/seccomp/app/gen_blacklist.py b/hostsidetests/seccomp/app/gen_blacklist.py
new file mode 100755
index 0000000..a104394
--- /dev/null
+++ b/hostsidetests/seccomp/app/gen_blacklist.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+#
+# This script generates syscall name to number mapping for supported
+# architectures. To update the output, runs:
+#
+# $ app/gen_blacklist.py > app/assets/syscalls.json
+#
+# TODO: Consider generating it in Android.mk/bp.
+
+import glob
+import json
+import os
+import subprocess
+
+_SUPPORTED_ARCHS = ['arm', 'arm64', 'x86', 'x86_64', 'mips', 'mips64']
+
+_INTERESTED_SYSCALLS = {
+ 'swapon': 'all',
+ 'swapoff': 'all',
+ 'add_key': 'all',
+ 'keyctl': 'all',
+ 'openat': 'all',
+ 'syncfs': 'all',
+ 'inotify_init': 'arm,x86,mips',
+}
+
+def create_syscall_name_to_number_map(arch, names):
+ arch_config = {
+ 'arm': {
+ 'uapi_class': 'asm-arm',
+ 'extra_cflags': [],
+ },
+ 'arm64': {
+ 'uapi_class': 'asm-arm64',
+ 'extra_cflags': [],
+ },
+ 'x86': {
+ 'uapi_class': 'asm-x86',
+ 'extra_cflags': ['-D__i386__'],
+ },
+ 'x86_64': {
+ 'uapi_class': 'asm-x86',
+ 'extra_cflags': [],
+ },
+ 'mips': {
+ 'uapi_class': 'asm-mips',
+ 'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI32'],
+ },
+ 'mips64': {
+ 'uapi_class': 'asm-mips',
+ 'extra_cflags': ['-D_MIPS_SIM=_MIPS_SIM_ABI64'],
+ }
+ }
+
+ # Run preprocessor over the __NR_syscall symbols, including unistd.h,
+ # to get the actual numbers
+ # TODO: The following code is forked from bionic/libc/tools/genseccomp.py.
+ # Figure out if we can de-duplicate them crossing cts project boundary.
+ prefix = '__SECCOMP_' # prefix to ensure no name collisions
+ kernel_uapi_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'),
+ 'bionic/libc/kernel/uapi')
+ cpp = subprocess.Popen(
+ [get_latest_clang_path(),
+ '-E', '-nostdinc',
+ '-I' + os.path.join(kernel_uapi_path,
+ arch_config[arch]['uapi_class']),
+ '-I' + os.path.join(kernel_uapi_path)
+ ]
+ + arch_config[arch]['extra_cflags']
+ + ['-'],
+ universal_newlines=True,
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ cpp.stdin.write('#include <asm/unistd.h>\n')
+ for name in names:
+ # In SYSCALLS.TXT, there are two arm-specific syscalls whose names start
+ # with __ARM__NR_. These we must simply write out as is.
+ if not name.startswith('__ARM_NR_'):
+ cpp.stdin.write(prefix + name + ', __NR_' + name + '\n')
+ else:
+ cpp.stdin.write(prefix + name + ', ' + name + '\n')
+ content = cpp.communicate()[0].split('\n')
+
+ # The input is now the preprocessed source file. This will contain a lot
+ # of junk from the preprocessor, but our lines will be in the format:
+ #
+ # __SECCOMP_${NAME}, (0 + value)
+ syscalls = {}
+ for line in content:
+ if not line.startswith(prefix):
+ continue
+ # We might pick up extra whitespace during preprocessing, so best to strip.
+ name, value = [w.strip() for w in line.split(',')]
+ name = name[len(prefix):]
+ # Note that some of the numbers were expressed as base + offset, so we
+ # need to eval, not just int
+ value = eval(value)
+ if name in syscalls:
+ raise Exception('syscall %s is re-defined' % name)
+ syscalls[name] = value
+ return syscalls
+
+def get_latest_clang_path():
+ candidates = sorted(glob.glob(os.path.join(os.getenv('ANDROID_BUILD_TOP'),
+ 'prebuilts/clang/host/linux-x86/clang-*')), reverse=True)
+ for clang_dir in candidates:
+ clang_exe = os.path.join(clang_dir, 'bin/clang')
+ if os.path.exists(clang_exe):
+ return clang_exe
+ raise FileNotFoundError('Cannot locate clang executable')
+
+def main():
+ dictionary = {}
+ for arch in _SUPPORTED_ARCHS:
+ syscall_names = []
+ for syscall in _INTERESTED_SYSCALLS.keys():
+ if (arch in _INTERESTED_SYSCALLS[syscall] or
+ 'all' == _INTERESTED_SYSCALLS[syscall]):
+ syscall_names.append(syscall)
+ dictionary[arch] = create_syscall_name_to_number_map(arch, syscall_names)
+
+ print(json.dumps(dictionary, sort_keys=True, indent=2))
+
+if __name__ == '__main__':
+ main()
diff --git a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
index 2a7bcb3..0f85146 100644
--- a/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
+++ b/hostsidetests/seccomp/app/src/android/seccomp/cts/app/SeccompDeviceTest.java
@@ -16,6 +16,17 @@
package android.seccomp.cts.app;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CpuFeatures;
+import org.json.JSONObject;
+import org.json.JSONException;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Assume;
@@ -23,9 +34,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import android.support.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.CpuFeatures;
-
/**
* Device-side tests for CtsSeccompHostTestCases
*/
@@ -35,68 +43,81 @@
System.loadLibrary("ctsseccomp_jni");
}
+ private JSONObject mSyscallMap;
+
+ @Before
+ public void initializeSyscallMap() throws IOException, JSONException {
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ AssetManager manager = context.getAssets();
+ String json = null;
+ try (InputStream is = manager.open("syscalls.json")) {
+ json = readInputStreamFully(is);
+ }
+ mSyscallMap = new JSONObject(json);
+ }
+
@Test
- public void testCTSSyscallBlocked() {
+ public void testCTSSyscallBlocked() throws JSONException {
+ String arch = getCurrentArch();
+
+ testBlocked(getSyscallNumber(arch, "add_key"));
+ testBlocked(getSyscallNumber(arch, "keyctl"));
+ testAllowed(getSyscallNumber(arch, "openat"));
+
if (CpuFeatures.isArm64Cpu()) {
- testBlocked(217); // __NR_add_key
- testBlocked(219); // __NR_keyctl
- testAllowed(56); // __NR_openat
-
- // b/35034743 - do not remove test without reading bug
- testAllowed(267); // __NR_fstatfs64
+ // b/35034743 - do not remove test without reading bug.
+ testAllowed(getSyscallNumber(arch, "syncfs"));
} else if (CpuFeatures.isArmCpu()) {
- testBlocked(309); // __NR_add_key
- testBlocked(311); // __NR_keyctl
- testAllowed(322); // __NR_openat
-
// b/35906875 - do not remove test without reading bug
- testAllowed(316); // __NR_inotify_init
- } else if (CpuFeatures.isX86_64Cpu()) {
- testBlocked(248); // __NR_add_key
- testBlocked(250); // __NR_keyctl
- testAllowed(257); // __NR_openat
- } else if (CpuFeatures.isX86Cpu()) {
- testBlocked(286); // __NR_add_key
- testBlocked(288); // __NR_keyctl
- testAllowed(295); // __NR_openat
- } else if (CpuFeatures.isMips64Cpu()) {
- testBlocked(5239); // __NR_add_key
- testBlocked(5241); // __NR_keyctl
- testAllowed(5247); // __NR_openat
- } else if (CpuFeatures.isMipsCpu()) {
- testBlocked(4280); // __NR_add_key
- testBlocked(4282); // __NR_keyctl
- testAllowed(4288); // __NR_openat
- } else {
- Assert.fail("Unsupported OS");
+ testAllowed(getSyscallNumber(arch, "inotify_init"));
}
}
@Test
- public void testCTSSwapOnOffBlocked() {
+ public void testCTSSwapOnOffBlocked() throws JSONException {
+ String arch = getCurrentArch();
+
+ testBlocked(getSyscallNumber(arch, "swapon"));
+ testBlocked(getSyscallNumber(arch, "swapoff"));
+ }
+
+ private int getSyscallNumber(String arch, String name) throws JSONException {
+ JSONObject perArchMap = mSyscallMap.getJSONObject(arch);
+ return perArchMap.getInt(name);
+ }
+
+ private static String getCurrentArch() {
if (CpuFeatures.isArm64Cpu()) {
- testBlocked(224); // __NR_swapon
- testBlocked(225); // __NR_swapoff
+ return "arm64";
} else if (CpuFeatures.isArmCpu()) {
- testBlocked(87); // __NR_swapon
- testBlocked(115); // __NR_swapoff
+ return "arm";
} else if (CpuFeatures.isX86_64Cpu()) {
- testBlocked(167); // __NR_swapon
- testBlocked(168); // __NR_swapoff
+ return "x86";
} else if (CpuFeatures.isX86Cpu()) {
- testBlocked(87); // __NR_swapon
- testBlocked(115); // __NR_swapoff
+ return "x86_64";
} else if (CpuFeatures.isMips64Cpu()) {
- testBlocked(5162); // __NR_swapon
- testBlocked(5163); // __NR_swapoff
+ return "mips64";
} else if (CpuFeatures.isMipsCpu()) {
- testBlocked(4087); // __NR_swapon
- testBlocked(4115); // __NR_swapoff
+ return "mips";
} else {
Assert.fail("Unsupported OS");
+ return null;
}
}
+ private String readInputStreamFully(InputStream is) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ byte[] buffer = new byte[4096];
+ while (is.available() > 0) {
+ int size = is.read(buffer);
+ if (size < 0) {
+ break;
+ }
+ sb.append(new String(buffer, 0, size));
+ }
+ return sb.toString();
+ }
+
private void testBlocked(int nr) {
Assert.assertTrue("Syscall " + nr + " not blocked", testSyscallBlocked(nr));
}
diff --git a/hostsidetests/security/AndroidTest.xml b/hostsidetests/security/AndroidTest.xml
index f414063..52c47cc 100755
--- a/hostsidetests/security/AndroidTest.xml
+++ b/hostsidetests/security/AndroidTest.xml
@@ -65,7 +65,7 @@
<!--__________________-->
<!-- Bulletin 2017-03 -->
<!-- Please add tests solely from this bulletin below to avoid merge conflict -->
-
+ <option name="push" value="CVE-2017-0334->/data/local/tmp/CVE-2017-0334" />
<option name="push" value="CVE-2016-8479->/data/local/tmp/CVE-2016-8479" />
<option name="push" value="CVE-2017-0508->/data/local/tmp/CVE-2017-0508" />
<option name="push" value="CVE-2017-0333->/data/local/tmp/CVE-2017-0333" />
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0334/Android.mk b/hostsidetests/security/securityPatch/CVE-2017-0334/Android.mk
new file mode 100644
index 0000000..166cd62
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0334/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := CVE-2017-0334
+LOCAL_SRC_FILES := poc.c
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+# Tag this module as a sts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts sts
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+LOCAL_ARM_MODE := arm
+LOCAL_CFLAGS = -Wall -Werror
+
+include $(BUILD_CTS_EXECUTABLE)
diff --git a/hostsidetests/security/securityPatch/CVE-2017-0334/poc.c b/hostsidetests/security/securityPatch/CVE-2017-0334/poc.c
new file mode 100644
index 0000000..14dd8e5
--- /dev/null
+++ b/hostsidetests/security/securityPatch/CVE-2017-0334/poc.c
@@ -0,0 +1,41 @@
+/**
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions vand
+ * limitations under the License.
+ */
+#define _GNU_SOURCE
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <fcntl.h>
+struct drm_tegra_open_channel {
+ __u32 client;
+ __u32 pad;
+ void* context;
+};
+#define tmp_DRM_IOCTL_TEGRA_OPEN_CHANNEL (int)3222299717
+int main()
+{
+ int fd, rc;
+ struct drm_tegra_open_channel open_args = {0,0,0};
+ open_args.client = 0x21;
+ fd = open("/dev/dri/renderD129", 0, 0);
+ rc = ioctl(fd, tmp_DRM_IOCTL_TEGRA_OPEN_CHANNEL, &open_args);
+
+ printf("Leaked ptr is %p\n", open_args.context);
+ return 0;
+}
diff --git a/hostsidetests/security/src/android/security/cts/Poc17_03.java b/hostsidetests/security/src/android/security/cts/Poc17_03.java
index 690b277..153accd 100644
--- a/hostsidetests/security/src/android/security/cts/Poc17_03.java
+++ b/hostsidetests/security/src/android/security/cts/Poc17_03.java
@@ -58,4 +58,16 @@
Thread.sleep(30000);
}
}
+
+ /**
+ * b/33245849
+ */
+ @SecurityTest
+ public void testPocCVE_2017_0334() throws Exception {
+ if (containsDriver(getDevice(), "/dev/dri/renderD129")) {
+ String out = AdbUtils.runPoc("CVE-2017-0334", getDevice());
+ assertNotMatchesMultiLine(".*Leaked ptr is (0x[fF]{6}[cC]0[a-fA-F0-9]{8}"
+ +"|0x[c-fC-F][a-fA-F0-9]{7}).*",out);
+ }
+ }
}
diff --git a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
index 6a89e26..a261730 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/ActivityManagerVrDisplayTests.java
@@ -43,23 +43,34 @@
private static final int VR_VIRTUAL_DISPLAY_HEIGHT = 900;
private static final int VR_VIRTUAL_DISPLAY_DPI = 320;
+ private boolean mVrHeadset;
+
@Before
@Override
public void setUp() throws Exception {
super.setUp();
assumeTrue(supportsVrMode());
+ mVrHeadset = isUiModeLockedToVrHeadset();
}
- private static class VrModeSession implements AutoCloseable {
+ /**
+ * VrModeSession is used to enable or disable persistent vr mode and the vr virtual display. For
+ * standalone vr devices, VrModeSession has no effect, because the device is already in
+ * persistent vr mode whenever it's on, and turning off persistent vr mode on a standalone vr
+ * device puts the device in a bad state.
+ */
+ private class VrModeSession implements AutoCloseable {
void enablePersistentVrMode() throws Exception {
+ if (mVrHeadset) { return; }
executeShellCommand("setprop vr_virtualdisplay true");
executeShellCommand("vr set-persistent-vr-mode-enabled true");
}
@Override
public void close() throws Exception {
+ if (mVrHeadset) { return; }
executeShellCommand("vr set-persistent-vr-mode-enabled false");
executeShellCommand("setprop vr_virtualdisplay false");
}
@@ -163,6 +174,12 @@
public void testActivityLaunchPostVr() throws Exception {
assumeTrue(supportsMultiDisplay());
+ if (mVrHeadset) {
+ // This test doesn't apply to a standalone vr device, since vr is always enabled, and
+ // there is no "post vr" behavior to verify.
+ return;
+ }
+
try (final VrModeSession vrModeSession = new VrModeSession()) {
// Put the device in persistent vr mode.
vrModeSession.enablePersistentVrMode();
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
index 372f22c..28afabc 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/ApnDatabaseTest.java
@@ -17,23 +17,19 @@
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.provider.Telephony.Carriers;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
-import android.test.InstrumentationTestCase;
import android.util.Log;
-import com.android.internal.telephony.uicc.IccUtils;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -53,6 +49,8 @@
private static final String TAG = "ApnDatabaseTest";
private ContentResolver mContentResolver;
+ private PackageManager mPackageManager;
+ private boolean mHasCellular;
private static final String NAME = "carrierName";
private static final String APN = "apn";
@@ -99,6 +97,12 @@
@Before
public void setUp() throws Exception {
mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
+ mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
+ // Checks whether the cellular stack should be running on this device.
+ mHasCellular = mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+ if (!mHasCellular) {
+ Log.e(TAG, "No cellular support, all tests will be skipped.");
+ }
}
private void failMessage() {
@@ -112,6 +116,7 @@
*/
@Test
public void testValidCase() {
+ if (!mHasCellular) return;
Uri uri = Carriers.CONTENT_URI;
// CONTENT_URI = Uri.parse("content://telephony/carriers");
// Create A set of column_name/value pairs to add to the database.
@@ -179,6 +184,7 @@
@Test
public void testQueryConflictCase() {
+ if (!mHasCellular) return;
String invalidColumn = "random";
Uri uri = Carriers.CONTENT_URI;
// CONTENT_URI = Uri.parse("content://telephony/carriers");
@@ -234,6 +240,7 @@
@Test
public void testUpdateConflictCase() {
+ if (!mHasCellular) return;
Uri uri = Carriers.CONTENT_URI;
// CONTENT_URI = Uri.parse("content://telephony/carriers");
// Create A set of column_name/value pairs to add to the database.
@@ -300,6 +307,7 @@
@Test
public void testDeleteConflictCase() {
+ if (!mHasCellular) return;
String invalidColumn = "random";
Uri uri = Carriers.CONTENT_URI;
// CONTENT_URI = Uri.parse("content://telephony/carriers");
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
index 63f8347..353b04a 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/NetworkScanApiTest.java
@@ -16,6 +16,7 @@
package android.carrierapi.cts;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -52,6 +53,7 @@
@RunWith(AndroidJUnit4.class)
public class NetworkScanApiTest {
private TelephonyManager mTelephonyManager;
+ private PackageManager mPackageManager;
private static final String TAG = "NetworkScanApiTest";
private int mNetworkScanStatus;
private static final int EVENT_NETWORK_SCAN_START = 100;
@@ -72,6 +74,7 @@
public void setUp() throws Exception {
mTelephonyManager = (TelephonyManager)
InstrumentationRegistry.getContext().getSystemService(Context.TELEPHONY_SERVICE);
+ mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
mTestHandlerThread = new NetworkScanHandlerThread(TAG);
mTestHandlerThread.start();
}
@@ -179,6 +182,11 @@
*/
@Test
public void testRequestNetworkScan() throws InterruptedException {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ // Checks whether the cellular stack should be running on this device.
+ Log.e(TAG, "No cellular support, the test will be skipped.");
+ return;
+ }
if (!mTelephonyManager.hasCarrierPrivileges()) {
fail("This test requires a SIM card with carrier privilege rule on it.");
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
index 80a7236..f101f3a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ImageDecoderTest.java
@@ -32,6 +32,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.ColorSpace;
import android.graphics.ImageDecoder;
import android.graphics.ImageDecoder.DecodeException;
import android.graphics.ImageDecoder.OnPartialImageListener;
@@ -43,6 +44,7 @@
import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.content.FileProvider;
import android.util.DisplayMetrics;
@@ -76,24 +78,28 @@
public final int width;
public final int height;
public final String mimeType;
+ public final ColorSpace colorSpace;
- public Record(int resId, int width, int height, String mimeType) {
+ Record(int resId, int width, int height, String mimeType, ColorSpace colorSpace) {
this.resId = resId;
this.width = width;
this.height = height;
this.mimeType = mimeType;
+ this.colorSpace = colorSpace;
}
}
+ private static final ColorSpace sSRGB = ColorSpace.get(ColorSpace.Named.SRGB);
+
private static final Record[] RECORDS = new Record[] {
- new Record(R.drawable.baseline_jpeg, 1280, 960, "image/jpeg"),
- new Record(R.drawable.png_test, 640, 480, "image/png"),
- new Record(R.drawable.gif_test, 320, 240, "image/gif"),
- new Record(R.drawable.bmp_test, 320, 240, "image/bmp"),
- new Record(R.drawable.webp_test, 640, 480, "image/webp"),
- new Record(R.drawable.google_chrome, 256, 256, "image/x-ico"),
- new Record(R.drawable.color_wheel, 128, 128, "image/x-ico"),
- new Record(R.raw.sample_1mp, 600, 338, "image/x-adobe-dng"),
+ new Record(R.drawable.baseline_jpeg, 1280, 960, "image/jpeg", sSRGB),
+ new Record(R.drawable.png_test, 640, 480, "image/png", sSRGB),
+ new Record(R.drawable.gif_test, 320, 240, "image/gif", sSRGB),
+ new Record(R.drawable.bmp_test, 320, 240, "image/bmp", sSRGB),
+ new Record(R.drawable.webp_test, 640, 480, "image/webp", sSRGB),
+ new Record(R.drawable.google_chrome, 256, 256, "image/x-ico", sSRGB),
+ new Record(R.drawable.color_wheel, 128, 128, "image/x-ico", sSRGB),
+ new Record(R.raw.sample_1mp, 600, 338, "image/x-adobe-dng", sSRGB),
};
// offset is how many bytes to offset the beginning of the image.
@@ -194,26 +200,27 @@
private interface SourceCreator extends IntFunction<ImageDecoder.Source> {};
- private SourceCreator mCreators[] = new SourceCreator[] {
- resId -> ImageDecoder.createSource(getAsByteBufferWrap(resId)),
- resId -> ImageDecoder.createSource(getAsDirectByteBuffer(resId)),
- resId -> ImageDecoder.createSource(getAsReadOnlyByteBuffer(resId)),
- resId -> ImageDecoder.createSource(getAsFile(resId)),
+ private SourceCreator[] mCreators = new SourceCreator[] {
+ resId -> ImageDecoder.createSource(getAsByteBufferWrap(resId)),
+ resId -> ImageDecoder.createSource(getAsDirectByteBuffer(resId)),
+ resId -> ImageDecoder.createSource(getAsReadOnlyByteBuffer(resId)),
+ resId -> ImageDecoder.createSource(getAsFile(resId)),
};
private interface UriCreator extends IntFunction<Uri> {};
- @Test
- public void testUris() {
- UriCreator creators[] = new UriCreator[] {
+ private UriCreator[] mUriCreators = new UriCreator[] {
resId -> getAsResourceUri(resId),
resId -> getAsFileUri(resId),
resId -> getAsContentUri(resId),
- };
+ };
+
+ @Test
+ public void testUris() {
for (Record record : RECORDS) {
int resId = record.resId;
String name = mRes.getResourceEntryName(resId);
- for (UriCreator f : creators) {
+ for (UriCreator f : mUriCreators) {
ImageDecoder.Source src = null;
Uri uri = f.apply(resId);
String fullName = name + ": " + uri.toString();
@@ -243,32 +250,19 @@
@Test
public void testInfo() {
- class Listener implements ImageDecoder.OnHeaderDecodedListener {
- public int mWidth;
- public int mHeight;
- public String mMimeType;
-
- @Override
- public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
- ImageDecoder.Source src) {
- mWidth = info.getSize().getWidth();
- mHeight = info.getSize().getHeight();
- mMimeType = info.getMimeType();
- }
- };
- Listener l = new Listener();
-
for (Record record : RECORDS) {
for (SourceCreator f : mCreators) {
ImageDecoder.Source src = f.apply(record.resId);
assertNotNull(src);
try {
- ImageDecoder.decodeDrawable(src, l);
- assertEquals(record.width, l.mWidth);
- assertEquals(record.height, l.mHeight);
- assertEquals(record.mimeType, l.mMimeType);
+ ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ assertEquals(record.width, info.getSize().getWidth());
+ assertEquals(record.height, info.getSize().getHeight());
+ assertEquals(record.mimeType, info.getMimeType());
+ assertSame(record.colorSpace, info.getColorSpace());
+ });
} catch (IOException e) {
- fail("Failed with exception " + e);
+ fail("Failed " + getAsResourceUri(record.resId) + " with exception " + e);
}
}
}
@@ -360,7 +354,7 @@
ImageDecoder.Source src) {
decoder.setAllocator(allocator);
if (doScale) {
- decoder.setSampleSize(2);
+ decoder.setTargetSampleSize(2);
}
if (doCrop) {
decoder.setCrop(new Rect(1, 1, info.getSize().getWidth() / 2 - 1,
@@ -425,13 +419,13 @@
ImageDecoder.Source src = mCreators[0].apply(resId);
try {
ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
- assertFalse(decoder.getRequireUnpremultiplied());
+ assertFalse(decoder.isUnpremultipliedRequired());
- decoder.setRequireUnpremultiplied(true);
- assertTrue(decoder.getRequireUnpremultiplied());
+ decoder.setUnpremultipliedRequired(true);
+ assertTrue(decoder.isUnpremultipliedRequired());
- decoder.setRequireUnpremultiplied(false);
- assertFalse(decoder.getRequireUnpremultiplied());
+ decoder.setUnpremultipliedRequired(false);
+ assertFalse(decoder.isUnpremultipliedRequired());
});
} catch (IOException e) {
fail("Failed " + getAsResourceUri(resId) + " with exception " + e);
@@ -459,7 +453,7 @@
assertNotNull(src);
Bitmap unpremul = ImageDecoder.decodeBitmap(src,
- (decoder, info, s) -> decoder.setRequireUnpremultiplied(true));
+ (decoder, info, s) -> decoder.setUnpremultipliedRequired(true));
assertNotNull(unpremul);
assertEquals(unpremul.hasAlpha(), hasAlpha[i]);
assertFalse(unpremul.isPremultiplied());
@@ -685,7 +679,7 @@
ImageDecoder.Source src = mCreators[0].apply(RECORDS[0].resId);
try {
ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- decoder.setRequireUnpremultiplied(true);
+ decoder.setUnpremultipliedRequired(true);
decoder.setPostProcessor((c) -> PixelFormat.UNKNOWN);
});
} catch (IOException e) {
@@ -748,7 +742,7 @@
ImageDecoder.Source src = mCreators[0].apply(record.resId);
try {
Drawable dr = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- decoder.setSampleSize(sampleSize);
+ decoder.setTargetSampleSize(sampleSize);
});
checkSampleSize(name, record.width, sampleSize, dr.getIntrinsicWidth());
@@ -774,7 +768,8 @@
ImageDecoder.Source src = f.apply(record.resId);
try {
Drawable dr = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- decoder.setSampleSize(supplySampleSize.applyAsInt(info.getSize()));
+ int sampleSize = supplySampleSize.applyAsInt(info.getSize());
+ decoder.setTargetSampleSize(sampleSize);
});
assertEquals(1, dr.getIntrinsicWidth());
} catch (IOException e) {
@@ -1056,13 +1051,13 @@
ImageDecoder.Source src = mCreators[0].apply(resId);
try {
ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- assertFalse(decoder.getMutable());
+ assertFalse(decoder.isMutableRequired());
- decoder.setMutable(true);
- assertTrue(decoder.getMutable());
+ decoder.setMutableRequired(true);
+ assertTrue(decoder.isMutableRequired());
- decoder.setMutable(false);
- assertFalse(decoder.getMutable());
+ decoder.setMutableRequired(false);
+ assertFalse(decoder.isMutableRequired());
});
} catch (IOException e) {
fail("Failed " + getAsResourceUri(resId) + " with exception " + e);
@@ -1081,7 +1076,7 @@
public void onHeaderDecoded(ImageDecoder decoder,
ImageDecoder.ImageInfo info,
ImageDecoder.Source src) {
- decoder.setMutable(true);
+ decoder.setMutableRequired(true);
decoder.setAllocator(allocator);
if (postProcess) {
decoder.setPostProcessor((c) -> PixelFormat.UNKNOWN);
@@ -1116,7 +1111,7 @@
ImageDecoder.Source src = mCreators[0].apply(RECORDS[0].resId);
try {
ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
- decoder.setMutable(true);
+ decoder.setMutableRequired(true);
decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE);
});
} catch (IOException e) {
@@ -1129,7 +1124,7 @@
ImageDecoder.Source src = mCreators[0].apply(RECORDS[0].resId);
try {
ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- decoder.setMutable(true);
+ decoder.setMutableRequired(true);
});
} catch (IOException e) {
fail("Failed with exception " + e);
@@ -1179,7 +1174,7 @@
public void testZeroSampleSize() {
ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
try {
- ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setSampleSize(0));
+ ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setTargetSampleSize(0));
} catch (IOException e) {
fail("Failed with exception " + e);
}
@@ -1189,7 +1184,7 @@
public void testNegativeSampleSize() {
ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
try {
- ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setSampleSize(-2));
+ ImageDecoder.decodeDrawable(src, (decoder, info, s) -> decoder.setTargetSampleSize(-2));
} catch (IOException e) {
fail("Failed with exception " + e);
}
@@ -1264,7 +1259,7 @@
public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
ImageDecoder.Source src) {
decoder.setTargetSize(width, height);
- decoder.setRequireUnpremultiplied(true);
+ decoder.setUnpremultipliedRequired(true);
}
};
ResizeListener l = new ResizeListener();
@@ -1297,7 +1292,7 @@
ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
Size size = info.getSize();
decoder.setTargetSize(size.getWidth() * 2, size.getHeight() * 2);
- decoder.setRequireUnpremultiplied(true);
+ decoder.setUnpremultipliedRequired(true);
});
} catch (IOException e) {
fail("Failed with exception " + e);
@@ -1314,7 +1309,7 @@
int width = size.getWidth() / 2 + 3;
int height = size.getHeight() / 2 + 3;
decoder.setTargetSize(width, height);
- decoder.setRequireUnpremultiplied(true);
+ decoder.setUnpremultipliedRequired(true);
});
} catch (IOException e) {
fail("Failed with exception " + e);
@@ -1455,7 +1450,7 @@
} catch (IOException e) {
fail("Failed with exception " + e);
}
- l.cachedDecoder.setSampleSize(2);
+ l.cachedDecoder.setTargetSampleSize(2);
}
@Test(expected=IllegalStateException.class)
@@ -1463,7 +1458,7 @@
ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
try {
ImageDecoder.decodeDrawable(src, (decoder, info, s) ->
- decoder.setRequireUnpremultiplied(true));
+ decoder.setUnpremultipliedRequired(true));
} catch (IOException e) {
fail("Failed with exception " + e);
}
@@ -1538,13 +1533,13 @@
@Test
public void testAlphaMaskNonGray() {
- // It is safe to call setDecodeAsAlphaMask on a non-gray image.
+ // It is safe to call setDecodeAsAlphaMaskEnabled on a non-gray image.
SourceCreator f = mCreators[0];
ImageDecoder.Source src = f.apply(R.drawable.png_test);
assertNotNull(src);
try {
Bitmap bm = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
- decoder.setDecodeAsAlphaMask(true);
+ decoder.setDecodeAsAlphaMaskEnabled(true);
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
});
assertNotNull(bm);
@@ -1562,7 +1557,7 @@
assertNotNull(src);
try {
ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- decoder.setDecodeAsAlphaMask(true);
+ decoder.setDecodeAsAlphaMaskEnabled(true);
decoder.setAllocator(ImageDecoder.ALLOCATOR_HARDWARE);
});
} catch (IOException e) {
@@ -1576,13 +1571,13 @@
ImageDecoder.Source src = mCreators[0].apply(resId);
try {
ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
- assertFalse(decoder.getDecodeAsAlphaMask());
+ assertFalse(decoder.isDecodeAsAlphaMaskEnabled());
- decoder.setDecodeAsAlphaMask(true);
- assertTrue(decoder.getDecodeAsAlphaMask());
+ decoder.setDecodeAsAlphaMaskEnabled(true);
+ assertTrue(decoder.isDecodeAsAlphaMaskEnabled());
- decoder.setDecodeAsAlphaMask(false);
- assertFalse(decoder.getDecodeAsAlphaMask());
+ decoder.setDecodeAsAlphaMaskEnabled(false);
+ assertFalse(decoder.isDecodeAsAlphaMaskEnabled());
});
} catch (IOException e) {
fail("Failed " + getAsResourceUri(resId) + " with exception " + e);
@@ -1598,7 +1593,7 @@
@Override
public void onHeaderDecoded(ImageDecoder decoder, ImageDecoder.ImageInfo info,
ImageDecoder.Source src) {
- decoder.setDecodeAsAlphaMask(true);
+ decoder.setDecodeAsAlphaMaskEnabled(true);
Size size = info.getSize();
if (doScale) {
decoder.setTargetSize(size.getWidth() / 2,
@@ -1997,44 +1992,201 @@
public final String name;
public final int width;
public final int height;
+ public final boolean isF16;
+ private final ColorSpace mColorSpace;
- AssetRecord(String name, int width, int height) {
+ AssetRecord(String name, int width, int height, boolean isF16, ColorSpace colorSpace) {
this.name = name;
this.width = width;
this.height = height;
+ this.isF16 = isF16;
+ mColorSpace = colorSpace;
+ }
+
+ public void checkColorSpace(ColorSpace requested, ColorSpace actual) {
+ assertNotNull(actual);
+ if (this.isF16) {
+ assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), actual);
+ } else if (requested != null) {
+ assertSame(requested, actual);
+ } else if (mColorSpace == null) {
+ assertEquals(this.name, "Unknown", actual.getName());
+ } else {
+ assertSame(this.name, mColorSpace, actual);
+ }
}
}
+ private static final AssetRecord[] ASSETS = new AssetRecord[] {
+ // A null ColorSpace means that the color space is "Unknown".
+ new AssetRecord("almost-red-adobe.png", 1, 1, false, null),
+ new AssetRecord("green-p3.png", 64, 64, false,
+ ColorSpace.get(ColorSpace.Named.DISPLAY_P3)),
+ new AssetRecord("green-srgb.png", 64, 64, false, sSRGB),
+ new AssetRecord("prophoto-rgba16f.png", 64, 64, true,
+ ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB)),
+ new AssetRecord("purple-cmyk.png", 64, 64, false, sSRGB),
+ new AssetRecord("purple-displayprofile.png", 64, 64, false, null),
+ new AssetRecord("red-adobergb.png", 64, 64, false,
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB)),
+ new AssetRecord("translucent-green-p3.png", 64, 64, false,
+ ColorSpace.get(ColorSpace.Named.DISPLAY_P3)),
+ };
+
@Test
public void testAssetSource() {
- AssetRecord[] records = new AssetRecord[] {
- new AssetRecord("almost-red-adobe.png", 1, 1),
- new AssetRecord("green-p3.png", 64, 64),
- new AssetRecord("green-srgb.png", 64, 64),
- new AssetRecord("prophoto-rgba16f.png", 64, 64),
- new AssetRecord("purple-cmyk.png", 64, 64),
- new AssetRecord("purple-displayprofile.png", 64, 64),
- new AssetRecord("red-adobergb.png", 64, 64),
- new AssetRecord("translucent-green-p3.png", 64, 64),
- };
-
- // CTS infrastructure fails to create F16 HARDWARE Bitmaps, so this switches
- // to using software.
- ImageDecoder.OnHeaderDecodedListener listener = (decoder, info, s) -> {
- decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
- };
-
AssetManager assets = mRes.getAssets();
- for (AssetRecord record : records) {
+ for (AssetRecord record : ASSETS) {
ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
try {
- Drawable dr = ImageDecoder.decodeDrawable(src, listener);
- assertNotNull(record.name, dr);
- assertEquals(record.name, record.width, dr.getIntrinsicWidth());
- assertEquals(record.name, record.height, dr.getIntrinsicHeight());
+ Bitmap bm = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
+ if (record.isF16) {
+ // CTS infrastructure fails to create F16 HARDWARE Bitmaps, so this
+ // switches to using software.
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ }
+
+ record.checkColorSpace(null, info.getColorSpace());
+ });
+ assertEquals(record.name, record.width, bm.getWidth());
+ assertEquals(record.name, record.height, bm.getHeight());
+ record.checkColorSpace(null, bm.getColorSpace());
} catch (IOException e) {
fail("Failed to decode asset " + record.name + " with " + e);
}
}
}
+
+ @Test
+ public void testTargetColorSpace() {
+ AssetManager assets = mRes.getAssets();
+ for (AssetRecord record : ASSETS) {
+ ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
+ for (ColorSpace cs : new ColorSpace[] {
+ sSRGB,
+ ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB),
+ ColorSpace.get(ColorSpace.Named.DISPLAY_P3),
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB),
+ ColorSpace.get(ColorSpace.Named.BT709),
+ ColorSpace.get(ColorSpace.Named.BT2020),
+ ColorSpace.get(ColorSpace.Named.DCI_P3),
+ ColorSpace.get(ColorSpace.Named.NTSC_1953),
+ ColorSpace.get(ColorSpace.Named.SMPTE_C),
+ ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB),
+ // FIXME: These will not match due to b/77276533.
+ // ColorSpace.get(ColorSpace.Named.LINEAR_SRGB),
+ // ColorSpace.get(ColorSpace.Named.ACES),
+ // ColorSpace.get(ColorSpace.Named.ACESCG),
+ }) {
+ try {
+ Bitmap bm = ImageDecoder.decodeBitmap(src, (decoder, info, s) -> {
+ if (record.isF16) {
+ // CTS infrastructure fails to create F16 HARDWARE Bitmaps, so this
+ // switches to using software.
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ }
+ decoder.setTargetColorSpace(cs);
+ });
+ record.checkColorSpace(cs, bm.getColorSpace());
+ } catch (IOException e) {
+ fail("Failed to decode asset " + record.name + " to " + cs + " with " + e);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testTargetColorSpaceNonRGB() {
+ ImageDecoder.Source src = mCreators[0].apply(R.drawable.png_test);
+ for (ColorSpace cs : new ColorSpace[] {
+ ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB),
+ ColorSpace.get(ColorSpace.Named.CIE_LAB),
+ ColorSpace.get(ColorSpace.Named.CIE_XYZ),
+ }) {
+ try {
+ ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ decoder.setTargetColorSpace(cs);
+ });
+ fail("Should have thrown an IllegalArgumentException for setTargetColorSpace("
+ + cs + ")!");
+ } catch (IOException e) {
+ fail("Failed to decode png_test with " + e);
+ } catch (IllegalArgumentException illegal) {
+ // This is expected.
+ }
+ }
+ }
+
+ private Bitmap drawToBitmap(Drawable dr) {
+ Bitmap bm = Bitmap.createBitmap(dr.getIntrinsicWidth(), dr.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bm);
+ dr.draw(canvas);
+ return bm;
+ }
+
+ private void testReuse(ImageDecoder.Source src, String name) {
+ Drawable first = null;
+ try {
+ first = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException e) {
+ fail("Failed on first decode of " + name + " using " + src + "!");
+ }
+
+ Drawable second = null;
+ try {
+ second = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ });
+ } catch (IOException e) {
+ fail("Failed on second decode of " + name + " using " + src + "!");
+ }
+
+ assertEquals(first.getIntrinsicWidth(), second.getIntrinsicWidth());
+ assertEquals(first.getIntrinsicHeight(), second.getIntrinsicHeight());
+
+ Bitmap bm1 = drawToBitmap(first);
+ Bitmap bm2 = drawToBitmap(second);
+ BitmapUtils.compareBitmaps(bm1, bm2);
+ }
+
+ @Test
+ @LargeTest
+ public void testReuse() {
+ for (Record record : RECORDS) {
+ String name = getAsResourceUri(record.resId).toString();
+ for (SourceCreator f : mCreators) {
+ ImageDecoder.Source src = f.apply(record.resId);
+ testReuse(src, name);
+ }
+
+ {
+ ImageDecoder.Source src = ImageDecoder.createSource(mRes, record.resId);
+ testReuse(src, name);
+ }
+
+ for (UriCreator f : mUriCreators) {
+ Uri uri = f.apply(record.resId);
+ ImageDecoder.Source src = ImageDecoder.createSource(mContentResolver, uri);
+ testReuse(src, uri.toString());
+ }
+
+ {
+ ImageDecoder.Source src = ImageDecoder.createSource(getAsFile(record.resId));
+ testReuse(src, name);
+ }
+ }
+
+ AssetManager assets = mRes.getAssets();
+ for (AssetRecord record : ASSETS) {
+ ImageDecoder.Source src = ImageDecoder.createSource(assets, record.name);
+ testReuse(src, record.name);
+ }
+
+
+ ImageDecoder.Source src = mCreators[0].apply(R.drawable.animated);
+ testReuse(src, "animated.gif");
+ }
}
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
index 51ee50e..b2c9d9b 100644
--- a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
@@ -152,4 +152,27 @@
// to query on the default network.
// assertEquals(-OsConstants.ENONET, runGetaddrinfoCheck(eNoNetHandle));
}
+
+ public void testNetworkHandle() {
+ // Test Network -> NetworkHandle -> Network results in the same Network.
+ for (Network network : getTestableNetworks()) {
+ long networkHandle = network.getNetworkHandle();
+ Network newNetwork = Network.fromNetworkHandle(networkHandle);
+ assertEquals(newNetwork, network);
+ }
+
+ // Test that only obfuscated handles are allowed.
+ try {
+ Network.fromNetworkHandle(100);
+ fail();
+ } catch (IllegalArgumentException e) {}
+ try {
+ Network.fromNetworkHandle(-1);
+ fail();
+ } catch (IllegalArgumentException e) {}
+ try {
+ Network.fromNetworkHandle(0);
+ fail();
+ } catch (IllegalArgumentException e) {}
+ }
}
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index 2088b7c..e5f6560 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -729,7 +729,7 @@
return bitmap.getPixel((int) (bitmap.getWidth() * xpos), (int) (bitmap.getHeight() * ypos));
}
- private void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
+ public static void assertBitmapQuadColor(Bitmap bitmap, int topLeft, int topRight,
int bottomLeft, int bottomRight) {
// Just quickly sample 4 pixels in the various regions.
assertEquals("Top left " + Integer.toHexString(topLeft) + ", actual= "
diff --git a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
index e71e275..3dad097 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewCtsActivity.java
@@ -22,6 +22,7 @@
import android.app.Activity;
import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.opengl.GLUtils;
import android.os.Bundle;
@@ -54,6 +55,8 @@
private CountDownLatch mEnterAnimationFence = new CountDownLatch(1);
private SurfaceTexture mSurface;
+ private int mSurfaceWidth;
+ private int mSurfaceHeight;
private int mSurfaceUpdatedCount;
static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
@@ -91,6 +94,16 @@
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ try {
+ runOnGLThread(this::doFinishGL);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ @Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
mEnterAnimationFence.countDown();
@@ -136,6 +149,10 @@
}
}
+ public TextureView getTextureView() {
+ return mTextureView;
+ }
+
public void waitForSurface() throws InterruptedException {
synchronized (mLock) {
while (mSurface == null) {
@@ -162,9 +179,34 @@
});
}
- public void finishGL() throws Throwable {
- if (mEglSurface == null) return;
- runOnGLThread(() -> doFinishGL());
+ interface DrawFrame {
+ void drawFrame(int width, int height);
+ }
+
+ public void drawFrame(Matrix transform, DrawFrame callback) throws Throwable {
+ CountDownLatch fence = new CountDownLatch(1);
+ runOnUiThread(() -> {
+ mTextureView.setTransform(transform);
+ fence.countDown();
+ });
+ waitForEnterAnimationComplete();
+ waitForSurface();
+ initGl();
+ fence.await();
+ int surfaceUpdateCount = mSurfaceUpdatedCount;
+ runOnGLThread(() -> {
+ callback.drawFrame(mSurfaceWidth, mSurfaceHeight);
+ if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+ throw new RuntimeException("Cannot swap buffers");
+ }
+ });
+ waitForSurfaceUpdateCount(surfaceUpdateCount + 1);
+ }
+
+ private static final Matrix IDENTITY = new Matrix();
+
+ public void drawFrame(DrawFrame callback) throws Throwable {
+ drawFrame(IDENTITY, callback);
}
public int waitForSurfaceUpdateCount(int updateCount) throws InterruptedException {
@@ -181,17 +223,25 @@
}
private void doFinishGL() {
- mEgl.eglDestroyContext(mEglDisplay, mEglContext);
- mEglContext = null;
- mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
- mEglSurface = null;
- mEgl.eglTerminate(mEglDisplay);
+ if (mEglSurface != null) {
+ mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+ mEglSurface = null;
+ }
+ if (mEglContext != null) {
+ mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+ mEglContext = null;
+ }
+ if (mEglDisplay != null) {
+ mEgl.eglTerminate(mEglDisplay);
+ }
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
synchronized (mLock) {
mSurface = surface;
+ mSurfaceWidth = width;
+ mSurfaceHeight = height;
mLock.notifyAll();
}
}
diff --git a/tests/tests/view/src/android/view/cts/TextureViewTest.java b/tests/tests/view/src/android/view/cts/TextureViewTest.java
index f66e137..8f284d9 100644
--- a/tests/tests/view/src/android/view/cts/TextureViewTest.java
+++ b/tests/tests/view/src/android/view/cts/TextureViewTest.java
@@ -16,24 +16,31 @@
package android.view.cts;
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.GL_SCISSOR_TEST;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+import static android.opengl.GLES20.glEnable;
+import static android.opengl.GLES20.glScissor;
+
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.PixelCopy;
+import android.view.TextureView;
import android.view.View;
import android.view.Window;
import com.android.compatibility.common.util.SynchronousPixelCopy;
import com.android.compatibility.common.util.WidgetTestUtils;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,72 +50,120 @@
@MediumTest
@RunWith(AndroidJUnit4.class)
public class TextureViewTest {
- private TextureViewCtsActivity mActivity;
- private SynchronousPixelCopy mPixelCopy;
- private Window mWindow;
@Rule
public ActivityTestRule<TextureViewCtsActivity> mActivityRule =
- new ActivityTestRule<>(TextureViewCtsActivity.class);
-
- @Before
- public void setup() {
- mActivity = mActivityRule.getActivity();
- mPixelCopy = new SynchronousPixelCopy();
- assertNotNull(mActivity);
- }
+ new ActivityTestRule<>(TextureViewCtsActivity.class, false, false);
@Test
public void testFirstFrames() throws Throwable {
- mActivity.waitForEnterAnimationComplete();
+ final TextureViewCtsActivity activity = mActivityRule.launchActivity(null);
+ activity.waitForEnterAnimationComplete();
final Point center = new Point();
+ final Window[] windowRet = new Window[1];
mActivityRule.runOnUiThread(() -> {
- View content = mActivity.findViewById(android.R.id.content);
+ View content = activity.findViewById(android.R.id.content);
int[] outLocation = new int[2];
content.getLocationOnScreen(outLocation);
center.x = outLocation[0] + (content.getWidth() / 2);
center.y = outLocation[1] + (content.getHeight() / 2);
- mWindow = mActivity.getWindow();
+ windowRet[0] = activity.getWindow();
});
+ final Window window = windowRet[0];
assertTrue(center.x > 0);
assertTrue(center.y > 0);
- waitForColor(center, Color.WHITE);
- mActivity.waitForSurface();
- mActivity.initGl();
+ waitForColor(window, center, Color.WHITE);
+ activity.waitForSurface();
+ activity.initGl();
int updatedCount;
- updatedCount = mActivity.waitForSurfaceUpdateCount(0);
+ updatedCount = activity.waitForSurfaceUpdateCount(0);
assertEquals(0, updatedCount);
- mActivity.drawColor(Color.GREEN);
- updatedCount = mActivity.waitForSurfaceUpdateCount(1);
+ activity.drawColor(Color.GREEN);
+ updatedCount = activity.waitForSurfaceUpdateCount(1);
assertEquals(1, updatedCount);
- assertEquals(Color.WHITE, getPixel(center));
+ assertEquals(Color.WHITE, getPixel(window, center));
WidgetTestUtils.runOnMainAndDrawSync(mActivityRule,
- mActivity.findViewById(android.R.id.content), () -> mActivity.removeCover());
+ activity.findViewById(android.R.id.content), () -> activity.removeCover());
- int color = waitForChange(center, Color.WHITE);
+ int color = waitForChange(window, center, Color.WHITE);
assertEquals(Color.GREEN, color);
- mActivity.drawColor(Color.BLUE);
- updatedCount = mActivity.waitForSurfaceUpdateCount(2);
+ activity.drawColor(Color.BLUE);
+ updatedCount = activity.waitForSurfaceUpdateCount(2);
assertEquals(2, updatedCount);
- color = waitForChange(center, color);
+ color = waitForChange(window, center, color);
assertEquals(Color.BLUE, color);
}
- private int getPixel(Point point) {
- Bitmap screenshot = Bitmap.createBitmap(mWindow.getDecorView().getWidth(),
- mWindow.getDecorView().getHeight(), Bitmap.Config.ARGB_8888);
- int result = mPixelCopy.request(mWindow, screenshot);
+ @Test
+ public void testScaling() throws Throwable {
+ final TextureViewCtsActivity activity = mActivityRule.launchActivity(null);
+ activity.drawFrame(TextureViewTest::drawGlQuad);
+ final Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+ mActivityRule.runOnUiThread(() -> {
+ activity.getTextureView().getBitmap(bitmap);
+ });
+ PixelCopyTest.assertBitmapQuadColor(bitmap,
+ Color.RED, Color.GREEN, Color.BLUE, Color.BLACK);
+ }
+
+ @Test
+ public void testRotateScale() throws Throwable {
+ final TextureViewCtsActivity activity = mActivityRule.launchActivity(null);
+ final TextureView textureView = activity.getTextureView();
+ WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, activity.getTextureView(), null);
+ Matrix rotate = new Matrix();
+ rotate.setRotate(180, textureView.getWidth() / 2, textureView.getHeight() / 2);
+ activity.drawFrame(rotate, TextureViewTest::drawGlQuad);
+ final Bitmap bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
+ mActivityRule.runOnUiThread(() -> {
+ activity.getTextureView().getBitmap(bitmap);
+ });
+ PixelCopyTest.assertBitmapQuadColor(bitmap,
+ Color.BLACK, Color.BLUE, Color.GREEN, Color.RED);
+ }
+
+ private static void drawGlQuad(int width, int height) {
+ int cx = width / 2;
+ int cy = height / 2;
+
+ glEnable(GL_SCISSOR_TEST);
+
+ glScissor(0, cy, cx, height - cy);
+ clearColor(Color.RED);
+
+ glScissor(cx, cy, width - cx, height - cy);
+ clearColor(Color.GREEN);
+
+ glScissor(0, 0, cx, cy);
+ clearColor(Color.BLUE);
+
+ glScissor(cx, 0, width - cx, cy);
+ clearColor(Color.BLACK);
+ }
+
+ private static void clearColor(int color) {
+ glClearColor(Color.red(color) / 255.0f,
+ Color.green(color) / 255.0f,
+ Color.blue(color) / 255.0f,
+ Color.alpha(color) / 255.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ private int getPixel(Window window, Point point) {
+ Bitmap screenshot = Bitmap.createBitmap(window.getDecorView().getWidth(),
+ window.getDecorView().getHeight(), Bitmap.Config.ARGB_8888);
+ int result = new SynchronousPixelCopy().request(window, screenshot);
assertEquals("Copy request failed", PixelCopy.SUCCESS, result);
int pixel = screenshot.getPixel(point.x, point.y);
screenshot.recycle();
return pixel;
}
- private void waitForColor(Point point, int color)
+ private void waitForColor(Window window, Point point, int color)
throws InterruptedException, TimeoutException {
for (int i = 0; i < 20; i++) {
- int pixel = getPixel(point);
+ int pixel = getPixel(window, point);
if (pixel == color) {
return;
}
@@ -117,10 +172,10 @@
throw new TimeoutException();
}
- private int waitForChange(Point point, int color)
+ private int waitForChange(Window window, Point point, int color)
throws InterruptedException, TimeoutException {
for (int i = 0; i < 30; i++) {
- int pixel = getPixel(point);
+ int pixel = getPixel(window, point);
if (pixel != color) {
return pixel;
}