Merge "RESTRICT AUTOMERGE Unset StrongAuthFlags when unlocking a user profile" into tm-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1ecbed4..aff21ef 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2850,18 +2850,14 @@
visitor.accept(Uri.parse(extras.getString(EXTRA_BACKGROUND_IMAGE_URI)));
}
- ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST);
+ ArrayList<Person> people = extras.getParcelableArrayList(EXTRA_PEOPLE_LIST,
+ Person.class);
if (people != null && !people.isEmpty()) {
for (Person p : people) {
visitor.accept(p.getIconUri());
}
}
- final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
- if (person != null) {
- visitor.accept(person.getIconUri());
- }
-
final RemoteInputHistoryItem[] history = extras.getParcelableArray(
Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS,
RemoteInputHistoryItem.class);
@@ -2873,10 +2869,16 @@
}
}
}
- }
- if (isStyle(MessagingStyle.class) && extras != null) {
- final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
+ // Extras for MessagingStyle. We visit them even if not isStyle(MessagingStyle), since
+ // Notification Listeners might use directly (without the isStyle check).
+ final Person person = extras.getParcelable(EXTRA_MESSAGING_PERSON, Person.class);
+ if (person != null) {
+ visitor.accept(person.getIconUri());
+ }
+
+ final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES,
+ Parcelable.class);
if (!ArrayUtils.isEmpty(messages)) {
for (MessagingStyle.Message message : MessagingStyle.Message
.getMessagesFromBundleArray(messages)) {
@@ -2889,7 +2891,8 @@
}
}
- final Parcelable[] historic = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
+ final Parcelable[] historic = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES,
+ Parcelable.class);
if (!ArrayUtils.isEmpty(historic)) {
for (MessagingStyle.Message message : MessagingStyle.Message
.getMessagesFromBundleArray(historic)) {
@@ -2902,15 +2905,14 @@
}
}
- visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON));
- }
+ visitIconUri(visitor, extras.getParcelable(EXTRA_CONVERSATION_ICON, Icon.class));
- if (isStyle(CallStyle.class) & extras != null) {
- Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON);
+ // Extras for CallStyle (same reason for visiting without checking isStyle).
+ Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON, Person.class);
if (callPerson != null) {
visitor.accept(callPerson.getIconUri());
}
- visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON));
+ visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class));
}
if (mBubbleMetadata != null) {
@@ -3413,8 +3415,11 @@
*
* @hide
*/
- public void setAllowlistToken(@Nullable IBinder token) {
- mAllowlistToken = token;
+ public void clearAllowlistToken() {
+ mAllowlistToken = null;
+ if (publicVersion != null) {
+ publicVersion.clearAllowlistToken();
+ }
}
/**
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 1c1f58a..187a21e 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -53,20 +53,6 @@
],
"presubmit-large": [
{
- "name": "CtsContentTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.content.pm.cts"
- }
- ]
- },
- {
"name": "CtsUsesNativeLibraryTest",
"options": [
{
@@ -152,6 +138,20 @@
],
"postsubmit": [
{
+ "name": "CtsContentTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "include-filter": "android.content.pm.cts"
+ }
+ ]
+ },
+ {
"name": "CtsAppSecurityHostTestCases",
"options": [
{
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 8f5c2a0..a753f96 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,3 +1,7 @@
# Bug component: 175220
+aprasath@google.com
+kumarashishg@google.com
+sarup@google.com
+anothermark@google.com
badhri@google.com
diff --git a/core/java/android/hardware/usb/UsbConfiguration.java b/core/java/android/hardware/usb/UsbConfiguration.java
index 66269cb..b25f47b 100644
--- a/core/java/android/hardware/usb/UsbConfiguration.java
+++ b/core/java/android/hardware/usb/UsbConfiguration.java
@@ -172,7 +172,8 @@
String name = in.readString();
int attributes = in.readInt();
int maxPower = in.readInt();
- Parcelable[] interfaces = in.readParcelableArray(UsbInterface.class.getClassLoader());
+ Parcelable[] interfaces = in.readParcelableArray(
+ UsbInterface.class.getClassLoader(), UsbInterface.class);
UsbConfiguration configuration = new UsbConfiguration(id, name, attributes, maxPower);
configuration.setInterfaces(interfaces);
return configuration;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index a6edb0f..f80d587 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1928,6 +1928,9 @@
cacheName = Settings.System.ALARM_ALERT_CACHE;
}
if (cacheName != null) {
+ if (!isValidAudioUri(name, value)) {
+ return false;
+ }
final File cacheFile = new File(
getRingtoneCacheDir(owningUserId), cacheName);
cacheFile.delete();
@@ -1960,6 +1963,34 @@
}
}
+ private boolean isValidAudioUri(String name, String uri) {
+ if (uri != null) {
+ Uri audioUri = Uri.parse(uri);
+ if (Settings.AUTHORITY.equals(
+ ContentProvider.getAuthorityWithoutUserId(audioUri.getAuthority()))) {
+ // Don't accept setting the default uri to self-referential URIs like
+ // Settings.System.DEFAULT_RINGTONE_URI, which is an alias to the value of this
+ // setting.
+ return false;
+ }
+ final String mimeType = getContext().getContentResolver().getType(audioUri);
+ if (mimeType == null) {
+ Slog.e(LOG_TAG,
+ "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+ + " ignored: failure to find mimeType (no access from this context?)");
+ return false;
+ }
+ if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg")
+ || mimeType.equals("application/x-flac"))) {
+ Slog.e(LOG_TAG,
+ "mutateSystemSetting for setting: " + name + " URI: " + audioUri
+ + " ignored: associated mimeType: " + mimeType + " is not an audio type");
+ return false;
+ }
+ }
+ return true;
+ }
+
private boolean hasWriteSecureSettingsPermission() {
// Write secure settings is a more protected permission. If caller has it we are good.
return getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
@@ -3101,6 +3132,15 @@
return settingsState.getSettingLocked(name);
}
+ private boolean shouldExcludeSettingFromReset(Setting setting, String prefix) {
+ // If a prefix was specified, exclude settings whose names don't start with it.
+ if (prefix != null && !setting.getName().startsWith(prefix)) {
+ return true;
+ }
+ // Never reset SECURE_FRP_MODE, as it could be abused to bypass FRP via RescueParty.
+ return Secure.SECURE_FRP_MODE.equals(setting.getName());
+ }
+
public void resetSettingsLocked(int type, int userId, String packageName, int mode,
String tag) {
resetSettingsLocked(type, userId, packageName, mode, tag, /*prefix=*/
@@ -3123,7 +3163,7 @@
Setting setting = settingsState.getSettingLocked(name);
if (packageName.equals(setting.getPackageName())) {
if ((tag != null && !tag.equals(setting.getTag()))
- || (prefix != null && !setting.getName().startsWith(prefix))) {
+ || shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -3143,7 +3183,7 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (settingsState.resetSettingLocked(name)) {
@@ -3163,7 +3203,7 @@
Setting setting = settingsState.getSettingLocked(name);
if (!SettingsState.isSystemPackage(getContext(),
setting.getPackageName())) {
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (setting.isDefaultFromSystem()) {
@@ -3186,7 +3226,7 @@
for (String name : settingsState.getSettingNamesLocked()) {
Setting setting = settingsState.getSettingLocked(name);
boolean someSettingChanged = false;
- if (prefix != null && !setting.getName().startsWith(prefix)) {
+ if (shouldExcludeSettingFromReset(setting, prefix)) {
continue;
}
if (setting.isDefaultFromSystem()) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index eaf0dcb..1c6d2b0 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -464,6 +464,31 @@
}
}
+ // To prevent FRP bypasses, the SECURE_FRP_MODE setting should not be reset when all other
+ // settings are reset. But it should still be possible to explicitly set its value.
+ @Test
+ public void testSecureFrpModeSettingCannotBeReset() throws Exception {
+ final String name = Settings.Secure.SECURE_FRP_MODE;
+ final String origValue = getSetting(SETTING_TYPE_GLOBAL, name);
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "1", false);
+ try {
+ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
+ for (int type : new int[] { SETTING_TYPE_GLOBAL, SETTING_TYPE_SECURE }) {
+ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+ resetSettingsViaShell(type, Settings.RESET_MODE_UNTRUSTED_CHANGES);
+ resetSettingsViaShell(type, Settings.RESET_MODE_TRUSTED_DEFAULTS);
+ }
+ // The value should still be "1". It should not have been reset to null.
+ assertEquals("1", getSetting(SETTING_TYPE_GLOBAL, name));
+ // It should still be possible to explicitly set the value to "0".
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, "0", false);
+ assertEquals("0", getSetting(SETTING_TYPE_GLOBAL, name));
+ } finally {
+ setSettingViaShell(SETTING_TYPE_GLOBAL, name, origValue, false);
+ assertEquals(origValue, getSetting(SETTING_TYPE_GLOBAL, name));
+ }
+ }
+
private void doTestQueryStringInBracketsViaProviderApiForType(int type) {
// Make sure we have a clean slate.
deleteStringViaProviderApi(type, FAKE_SETTING_NAME);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 0309d21..c5fd4c1c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -62,6 +62,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.ViewController;
@@ -250,6 +251,7 @@
showPrimarySecurityScreen(false);
}
};
+ private final DeviceProvisionedController mDeviceProvisionedController;
private KeyguardSecurityContainerController(KeyguardSecurityContainer view,
AdminSecondaryLockScreenController.Factory adminSecondaryLockScreenControllerFactory,
@@ -267,7 +269,9 @@
UserSwitcherController userSwitcherController,
FeatureFlags featureFlags,
GlobalSettings globalSettings,
- SessionTracker sessionTracker) {
+ SessionTracker sessionTracker,
+ DeviceProvisionedController deviceProvisionedController
+ ) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -287,6 +291,7 @@
mFeatureFlags = featureFlags;
mGlobalSettings = globalSettings;
mSessionTracker = sessionTracker;
+ mDeviceProvisionedController = deviceProvisionedController;
}
@Override
@@ -469,8 +474,11 @@
case SimPuk:
// Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
- if (securityMode == SecurityMode.None || mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser())) {
+ boolean isLockscreenDisabled = mLockPatternUtils.isLockScreenDisabled(
+ KeyguardUpdateMonitor.getCurrentUser())
+ || !mDeviceProvisionedController.isUserSetup(targetUserId);
+
+ if (securityMode == SecurityMode.None && isLockscreenDisabled) {
finish = true;
eventSubtype = BOUNCER_DISMISS_SIM;
uiEvent = BouncerUiEvent.BOUNCER_DISMISS_SIM;
@@ -676,6 +684,7 @@
private final FeatureFlags mFeatureFlags;
private final UserSwitcherController mUserSwitcherController;
private final SessionTracker mSessionTracker;
+ private final DeviceProvisionedController mDeviceProvisionedController;
@Inject
Factory(KeyguardSecurityContainer view,
@@ -694,7 +703,8 @@
UserSwitcherController userSwitcherController,
FeatureFlags featureFlags,
GlobalSettings globalSettings,
- SessionTracker sessionTracker) {
+ SessionTracker sessionTracker,
+ DeviceProvisionedController deviceProvisionedController) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
@@ -711,6 +721,7 @@
mGlobalSettings = globalSettings;
mUserSwitcherController = userSwitcherController;
mSessionTracker = sessionTracker;
+ mDeviceProvisionedController = deviceProvisionedController;
}
public KeyguardSecurityContainerController create(
@@ -720,7 +731,8 @@
mKeyguardUpdateMonitor, mKeyguardSecurityModel, mMetricsLogger, mUiEventLogger,
mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
- mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker);
+ mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker,
+ mDeviceProvisionedController);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 3eb58bb..ec76f43 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -38,6 +38,7 @@
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.ui.CanUseIconPredicate
import com.android.systemui.controls.ui.RenderInfo
private typealias ModelFavoriteChanger = (String, Boolean) -> Unit
@@ -51,7 +52,8 @@
* @property elevation elevation of each control view
*/
class ControlAdapter(
- private val elevation: Float
+ private val elevation: Float,
+ private val currentUserId: Int,
) : RecyclerView.Adapter<Holder>() {
companion object {
@@ -107,7 +109,8 @@
background = parent.context.getDrawable(
R.drawable.control_background_ripple)
},
- model?.moveHelper // Indicates that position information is needed
+ currentUserId,
+ model?.moveHelper, // Indicates that position information is needed
) { id, favorite ->
model?.changeFavoriteStatus(id, favorite)
}
@@ -212,8 +215,9 @@
*/
internal class ControlHolder(
view: View,
+ currentUserId: Int,
val moveHelper: ControlsModel.MoveHelper?,
- val favoriteCallback: ModelFavoriteChanger
+ val favoriteCallback: ModelFavoriteChanger,
) : Holder(view) {
private val favoriteStateDescription =
itemView.context.getString(R.string.accessibility_control_favorite)
@@ -228,6 +232,7 @@
visibility = View.VISIBLE
}
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val accessibilityDelegate = ControlHolderAccessibilityDelegate(
this::stateDescription,
this::getLayoutPosition,
@@ -287,7 +292,9 @@
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
icon.imageTintList = null
- ci.customIcon?.let {
+ ci.customIcon
+ ?.takeIf(canUseIconPredicate)
+ ?.let {
icon.setImageIcon(it)
} ?: run {
icon.setImageDrawable(ri.icon)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index f611c3e..d6cbb02 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -180,7 +180,7 @@
val elevation = resources.getFloat(R.dimen.control_card_elevation)
val recyclerView = requireViewById<RecyclerView>(R.id.list)
recyclerView.alpha = 0.0f
- val adapter = ControlAdapter(elevation).apply {
+ val adapter = ControlAdapter(elevation, currentUserTracker.currentUserId).apply {
registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
var hasAnimated = false
override fun onChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index dca52a9..a5cc078 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -164,7 +164,7 @@
}
executor.execute {
- structurePager.adapter = StructureAdapter(listOfStructures)
+ structurePager.adapter = StructureAdapter(listOfStructures, currentUserTracker.currentUserId)
structurePager.setCurrentItem(structureIndex)
if (error) {
statusText.text = resources.getString(R.string.controls_favorite_load_error,
@@ -210,7 +210,7 @@
structurePager.alpha = 0.0f
pageIndicator.alpha = 0.0f
structurePager.apply {
- adapter = StructureAdapter(emptyList())
+ adapter = StructureAdapter(emptyList(), currentUserTracker.currentUserId)
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
index 747bcbe..5977d37 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -24,13 +24,15 @@
import com.android.systemui.R
class StructureAdapter(
- private val models: List<StructureContainer>
+ private val models: List<StructureContainer>,
+ private val currentUserId: Int,
) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder {
val layoutInflater = LayoutInflater.from(parent.context)
return StructureHolder(
- layoutInflater.inflate(R.layout.controls_structure_page, parent, false)
+ layoutInflater.inflate(R.layout.controls_structure_page, parent, false),
+ currentUserId,
)
}
@@ -40,7 +42,8 @@
holder.bind(models[index].model)
}
- class StructureHolder(view: View) : RecyclerView.ViewHolder(view) {
+ class StructureHolder(view: View, currentUserId: Int) :
+ RecyclerView.ViewHolder(view) {
private val recyclerView: RecyclerView
private val controlAdapter: ControlAdapter
@@ -48,7 +51,7 @@
init {
recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll)
val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation)
- controlAdapter = ControlAdapter(elevation)
+ controlAdapter = ControlAdapter(elevation, currentUserId)
setUpRecyclerView()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt
new file mode 100644
index 0000000..61c2123
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/CanUseIconPredicate.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 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.systemui.controls.ui
+
+import android.content.ContentProvider
+import android.graphics.drawable.Icon
+
+class CanUseIconPredicate(private val currentUserId: Int) : (Icon) -> Boolean {
+
+ override fun invoke(icon: Icon): Boolean =
+ if (icon.type == Icon.TYPE_URI || icon.type == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ ContentProvider.getUserIdFromUri(icon.uri, currentUserId) == currentUserId
+ } else {
+ true
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 6a9aaf8..9310628 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -68,7 +68,8 @@
val bgExecutor: DelayableExecutor,
val controlActionCoordinator: ControlActionCoordinator,
val controlsMetricsLogger: ControlsMetricsLogger,
- val uid: Int
+ val uid: Int,
+ val currentUserId: Int,
) {
companion object {
@@ -85,29 +86,9 @@
private val ATTR_DISABLED = intArrayOf(-android.R.attr.state_enabled)
const val MIN_LEVEL = 0
const val MAX_LEVEL = 10000
-
- fun findBehaviorClass(
- status: Int,
- template: ControlTemplate,
- deviceType: Int
- ): Supplier<out Behavior> {
- return when {
- status != Control.STATUS_OK -> Supplier { StatusBehavior() }
- template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() }
- template is ThumbnailTemplate -> Supplier { ThumbnailBehavior() }
-
- // Required for legacy support, or where cameras do not use the new template
- deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() }
- template is ToggleTemplate -> Supplier { ToggleBehavior() }
- template is StatelessTemplate -> Supplier { TouchBehavior() }
- template is ToggleRangeTemplate -> Supplier { ToggleRangeBehavior() }
- template is RangeTemplate -> Supplier { ToggleRangeBehavior() }
- template is TemperatureControlTemplate -> Supplier { TemperatureControlBehavior() }
- else -> Supplier { DefaultBehavior() }
- }
- }
}
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val toggleBackgroundIntensity: Float = layout.context.resources
.getFraction(R.fraction.controls_toggle_bg_intensity, 1, 1)
private var stateAnimator: ValueAnimator? = null
@@ -147,6 +128,27 @@
status.setSelected(true)
}
+ fun findBehaviorClass(
+ status: Int,
+ template: ControlTemplate,
+ deviceType: Int
+ ): Supplier<out Behavior> {
+ return when {
+ status != Control.STATUS_OK -> Supplier { StatusBehavior() }
+ template == ControlTemplate.NO_TEMPLATE -> Supplier { TouchBehavior() }
+ template is ThumbnailTemplate -> Supplier { ThumbnailBehavior(currentUserId) }
+
+ // Required for legacy support, or where cameras do not use the new template
+ deviceType == DeviceTypes.TYPE_CAMERA -> Supplier { TouchBehavior() }
+ template is ToggleTemplate -> Supplier { ToggleBehavior() }
+ template is StatelessTemplate -> Supplier { TouchBehavior() }
+ template is ToggleRangeTemplate -> Supplier { ToggleRangeBehavior() }
+ template is RangeTemplate -> Supplier { ToggleRangeBehavior() }
+ template is TemperatureControlTemplate -> Supplier { TemperatureControlBehavior() }
+ else -> Supplier { DefaultBehavior() }
+ }
+ }
+
fun bindData(cws: ControlWithState, isLocked: Boolean) {
// If an interaction is in progress, the update may visually interfere with the action the
// action the user wants to make. Don't apply the update, and instead assume a new update
@@ -473,7 +475,9 @@
status.setTextColor(color)
- control?.getCustomIcon()?.let {
+ control?.customIcon
+ ?.takeIf(canUseIconPredicate)
+ ?.let {
icon.setImageIcon(it)
icon.imageTintList = it.tintList
} ?: run {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 1268250..aa390d9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -411,7 +411,8 @@
bgExecutor,
controlActionCoordinator,
controlsMetricsLogger,
- selected.uid
+ selected.uid,
+ controlsController.get().currentUserId,
)
cvh.bindData(it, false /* isLocked, will be ignored on initial load */)
controlViewsById.put(key, cvh)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index a7dc09b..39d6970 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -63,7 +63,7 @@
// interactions (touch, range)
subBehavior = cvh.bindBehavior(
subBehavior,
- ControlViewHolder.findBehaviorClass(
+ cvh.findBehaviorClass(
control.status,
subTemplate,
control.deviceType
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
index c2168aa..0b57e79 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
@@ -33,7 +33,7 @@
* Supports display of static images on the background of the tile. When marked active, the title
* and subtitle will not be visible. To be used with {@link Thumbnailtemplate} only.
*/
-class ThumbnailBehavior : Behavior {
+class ThumbnailBehavior(currentUserId: Int) : Behavior {
lateinit var template: ThumbnailTemplate
lateinit var control: Control
lateinit var cvh: ControlViewHolder
@@ -42,6 +42,7 @@
private var shadowRadius: Float = 0f
private var shadowColor: Int = 0
+ private val canUseIconPredicate = CanUseIconPredicate(currentUserId)
private val enabled: Boolean
get() = template.isActive()
@@ -80,11 +81,16 @@
cvh.status.setShadowLayer(shadowOffsetX, shadowOffsetY, shadowRadius, shadowColor)
cvh.bgExecutor.execute {
- val drawable = template.getThumbnail().loadDrawable(cvh.context)
+ val drawable = template.thumbnail
+ ?.takeIf(canUseIconPredicate)
+ ?.loadDrawable(cvh.context)
cvh.uiExecutor.execute {
val radius = cvh.context.getResources()
.getDimensionPixelSize(R.dimen.control_corner_radius).toFloat()
- clipLayer.setDrawable(CornerDrawable(drawable, radius))
+ // TODO(b/290037843): Add a placeholder
+ drawable?.let {
+ clipLayer.drawable = CornerDrawable(it, radius)
+ }
clipLayer.setColorFilter(BlendModeColorFilter(cvh.context.resources
.getColor(R.color.control_thumbnail_tint), BlendMode.LUMINOSITY))
cvh.applyRenderInfo(enabled, colorOffset)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index efc9921..e717656 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -55,6 +55,7 @@
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.util.settings.GlobalSettings;
@@ -164,7 +165,8 @@
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
- mSessionTracker).create(mSecurityCallback);
+ mSessionTracker, mock(DeviceProvisionedController.class))
+ .create(mSecurityCallback);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
new file mode 100644
index 0000000..bfdb923
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/CanUseIconPredicateTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2023 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.systemui.controls.ui
+
+import android.content.ContentProvider
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CanUseIconPredicateTest : SysuiTestCase() {
+
+ private companion object {
+ const val USER_ID_1 = 1
+ const val USER_ID_2 = 2
+ }
+
+ val underTest: CanUseIconPredicate = CanUseIconPredicate(USER_ID_1)
+
+ @Test
+ fun testReturnsFalseForDifferentUser() {
+ val user2Icon =
+ Icon.createWithContentUri(
+ ContentProvider.createContentUriForUser(
+ Uri.parse("content://test"),
+ UserHandle.of(USER_ID_2)
+ )
+ )
+
+ assertThat(underTest.invoke(user2Icon)).isFalse()
+ }
+
+ @Test
+ fun testReturnsTrueForCorrectUser() {
+ val user1Icon =
+ Icon.createWithContentUri(
+ ContentProvider.createContentUriForUser(
+ Uri.parse("content://test"),
+ UserHandle.of(USER_ID_1)
+ )
+ )
+
+ assertThat(underTest.invoke(user1Icon)).isTrue()
+ }
+
+ @Test
+ fun testReturnsTrueForUriWithoutUser() {
+ val uriIcon = Icon.createWithContentUri(Uri.parse("content://test"))
+
+ assertThat(underTest.invoke(uriIcon)).isTrue()
+ }
+
+ @Test
+ fun testReturnsTrueForNonUriIcon() {
+ val bitmapIcon = Icon.createWithBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
+
+ assertThat(underTest.invoke(bitmapIcon)).isTrue()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
index d3c465d..42f28c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
@@ -66,7 +66,8 @@
FakeExecutor(clock),
mock(ControlActionCoordinator::class.java),
mock(ControlsMetricsLogger::class.java),
- uid = 100
+ uid = 100,
+ 0,
)
val cws = ControlWithState(
diff --git a/services/core/java/com/android/server/PendingIntentUtils.java b/services/core/java/com/android/server/PendingIntentUtils.java
index 1600101..a72a4d25 100644
--- a/services/core/java/com/android/server/PendingIntentUtils.java
+++ b/services/core/java/com/android/server/PendingIntentUtils.java
@@ -34,6 +34,7 @@
public static Bundle createDontSendToRestrictedAppsBundle(@Nullable Bundle bundle) {
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setDontSendToRestrictedApps(true);
+ options.setPendingIntentBackgroundActivityLaunchAllowed(false);
if (bundle == null) {
return options.toBundle();
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 570c8d4..a71cd35 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2988,6 +2988,22 @@
}
}
+ /**
+ * Enforces that the uid of the caller matches the uid of the package.
+ *
+ * @param packageName the name of the package to match uid against.
+ * @param callingUid the uid of the caller.
+ * @throws SecurityException if the calling uid doesn't match uid of the package.
+ */
+ private void enforceCallingPackage(String packageName, int callingUid) {
+ final int userId = UserHandle.getUserId(callingUid);
+ final int packageUid = getPackageManagerInternal().getPackageUid(packageName,
+ /*flags=*/ 0, userId);
+ if (packageUid != callingUid) {
+ throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+ }
+ }
+
@Override
public void setPackageScreenCompatMode(String packageName, int mode) {
mActivityTaskManager.setPackageScreenCompatMode(packageName, mode);
@@ -12918,13 +12934,16 @@
// A backup agent has just come up
@Override
public void backupAgentCreated(String agentPackageName, IBinder agent, int userId) {
+ final int callingUid = Binder.getCallingUid();
+ enforceCallingPackage(agentPackageName, callingUid);
+
// Resolve the target user id and enforce permissions.
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId = mUserController.handleIncomingUser(Binder.getCallingPid(), callingUid,
userId, /* allowAll */ false, ALLOW_FULL_ONLY, "backupAgentCreated", null);
if (DEBUG_BACKUP) {
Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+ " callingUserId = " + UserHandle.getCallingUserId() + " userId = " + userId
- + " callingUid = " + Binder.getCallingUid() + " uid = " + Process.myUid());
+ + " callingUid = " + callingUid + " uid = " + Process.myUid());
}
synchronized(this) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f2f6dca..4ddc72e 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4341,7 +4341,7 @@
// Remove background token before returning notification to untrusted app, this
// ensures the app isn't able to perform background operations that are
// associated with notification interactions.
- notification.setAllowlistToken(null);
+ notification.clearAllowlistToken();
return new StatusBarNotification(
sbn.getPackageName(),
sbn.getOpPkg(),
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 9c74dd7..9d76072 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -81,7 +81,7 @@
]
}
],
- "presubmit-large": [
+ "postsubmit": [
{
"name": "CtsContentTestCases",
"options": [
@@ -95,9 +95,7 @@
"include-filter": "android.content.pm.cts"
}
]
- }
- ],
- "postsubmit": [
+ },
{
"name": "CtsPermissionTestCases",
"options": [
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 66524edf..1386bbf 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -254,12 +254,45 @@
}
final long identity = Binder.clearCallingIdentity();
try {
- return userState.getCustomPrinterIcon(printerId);
+ Icon icon = userState.getCustomPrinterIcon(printerId);
+ return validateIconUserBoundary(icon);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ /**
+ * Validates the custom printer icon to see if it's not in the calling user space.
+ * If the condition is not met, return null. Otherwise, return the original icon.
+ *
+ * @param icon
+ * @return icon (validated)
+ */
+ private Icon validateIconUserBoundary(Icon icon) {
+ // Refer to Icon#getUriString for context. The URI string is invalid for icons of
+ // incompatible types.
+ if (icon != null && (icon.getType() == Icon.TYPE_URI
+ || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) {
+ String encodedUser = icon.getUri().getEncodedUserInfo();
+
+ // If there is no encoded user, the URI is calling into the calling user space
+ if (encodedUser != null) {
+ int userId = Integer.parseInt(encodedUser);
+ // resolve encoded user
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+
+ synchronized (mLock) {
+ // Only the current group members can get the printer icons.
+ if (resolveCallingProfileParentLocked(resolvedUserId)
+ != getCurrentUserId()) {
+ return null;
+ }
+ }
+ }
+ }
+ return icon;
+ }
+
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
if (printJobId == null) {
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java
index ef6253b..8707a4f 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageManagerTests.java
@@ -56,7 +56,7 @@
import android.os.RemoteException;
import android.os.StatFs;
import android.os.SystemClock;
-import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.Postsubmit;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.system.ErrnoException;
@@ -94,7 +94,7 @@
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
-@Presubmit
+@Postsubmit
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e62f3b8..8c60178 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5356,6 +5356,49 @@
}
@Test
+ public void testVisitUris_styleExtrasWithoutStyle() {
+ Notification notification = new Notification.Builder(mContext, "a")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Notification.MessagingStyle messagingStyle = new Notification.MessagingStyle(
+ personWithIcon("content://user"))
+ .addHistoricMessage(new Notification.MessagingStyle.Message("Heyhey!",
+ System.currentTimeMillis(),
+ personWithIcon("content://historicalMessenger")))
+ .addMessage(new Notification.MessagingStyle.Message("Are you there",
+ System.currentTimeMillis(),
+ personWithIcon("content://messenger")))
+ .setShortcutIcon(
+ Icon.createWithContentUri("content://conversationShortcut"));
+ messagingStyle.addExtras(notification.extras); // Instead of Builder.setStyle(style).
+
+ Notification.CallStyle callStyle = Notification.CallStyle.forOngoingCall(
+ personWithIcon("content://caller"),
+ PendingIntent.getActivity(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE))
+ .setVerificationIcon(Icon.createWithContentUri("content://callVerification"));
+ callStyle.addExtras(notification.extras); // Same.
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ notification.visitUris(visitor);
+
+ verify(visitor).accept(eq(Uri.parse("content://user")));
+ verify(visitor).accept(eq(Uri.parse("content://historicalMessenger")));
+ verify(visitor).accept(eq(Uri.parse("content://messenger")));
+ verify(visitor).accept(eq(Uri.parse("content://conversationShortcut")));
+ verify(visitor).accept(eq(Uri.parse("content://caller")));
+ verify(visitor).accept(eq(Uri.parse("content://callVerification")));
+ }
+
+ private static Person personWithIcon(String iconUri) {
+ return new Person.Builder()
+ .setName("Mr " + iconUri)
+ .setIcon(Icon.createWithContentUri(iconUri))
+ .build();
+ }
+
+ @Test
public void testVisitUris_wearableExtender() {
Icon actionIcon = Icon.createWithContentUri("content://media/action");
Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index 60172a3..d35dbb56 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,3 +1,7 @@
+aprasath@google.com
+kumarashishg@google.com
+sarup@google.com
+anothermark@google.com
badhri@google.com
elaurent@google.com
albertccwang@google.com