From 11b11215aa18f782267d74e7a90a397ad1fdce10 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Mon, 2 Jun 2025 09:40:27 +0000 Subject: [PATCH 1/5] Prevent SettingsSliceProvider from accessing unused packages DISABLE_TOPIC_PROTECTOR Bug: 388034510 Test: adb shell cmd slice get-permissions com.android.settings.slices atest SettingsSliceProviderTest Flag: EXEMPT security issue Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:4c0413484999d7ae970954dd9da35ccec6863d59 Merged-In: Ia655fbb9cb46f192559b82f957e3b2f0dd86946c Change-Id: Ia655fbb9cb46f192559b82f957e3b2f0dd86946c --- res/values/config.xml | 3 +++ .../slices/SettingsSliceProvider.java | 20 +++++++++++++++---- tests/robotests/res/values-mcc998/config.xml | 3 +++ tests/robotests/res/values-mcc999/config.xml | 5 +++++ .../slices/SettingsSliceProviderTest.java | 19 ++++++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 4b638b25552..3a9f92d3dc1 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -201,6 +201,9 @@ + + + diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index ec60f44110a..e8dcc3c5d72 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -29,6 +29,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.StrictMode; import android.os.UserManager; import android.provider.Settings; @@ -375,19 +376,30 @@ public class SettingsSliceProvider extends SliceProvider { if (descendants == null) { Log.d(TAG, "No descendants to grant permission with, skipping."); } - final String[] allowlistPackages = + final List allowlist = new ArrayList<>(); + final String[] packages = context.getResources().getStringArray(R.array.slice_allowlist_package_names); - if (allowlistPackages == null || allowlistPackages.length == 0) { + if (packages != null) { + allowlist.addAll(Arrays.asList(packages)); + } + if (Build.IS_DEBUGGABLE) { + final String[] devPackages = context.getResources().getStringArray( + R.array.slice_allowlist_package_names_for_dev); + if (devPackages != null) { + allowlist.addAll(Arrays.asList(devPackages)); + } + } + if (allowlist.size() == 0) { Log.d(TAG, "No packages to allowlist, skipping."); return; } else { Log.d(TAG, String.format( "Allowlisting %d uris to %d pkgs.", - descendants.size(), allowlistPackages.length)); + descendants.size(), allowlist.size())); } final SliceManager sliceManager = context.getSystemService(SliceManager.class); for (Uri descendant : descendants) { - for (String toPackage : allowlistPackages) { + for (String toPackage : allowlist) { sliceManager.grantSlicePermission(toPackage, descendant); } } diff --git a/tests/robotests/res/values-mcc998/config.xml b/tests/robotests/res/values-mcc998/config.xml index 6572b1485b5..18174983a1f 100644 --- a/tests/robotests/res/values-mcc998/config.xml +++ b/tests/robotests/res/values-mcc998/config.xml @@ -17,4 +17,7 @@ + + + diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml index 2183b47a37a..c5b01c93d28 100644 --- a/tests/robotests/res/values-mcc999/config.xml +++ b/tests/robotests/res/values-mcc999/config.xml @@ -86,6 +86,11 @@ com.android.settings.slice_allowlist_package + + + com.android.settings.slice_allowlist_package_dev + + test@test.test diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index 84c8586602b..2f7107c43e5 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -80,6 +80,7 @@ import org.robolectric.annotation.Resetter; import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowAccessibilityManager; import org.robolectric.shadows.ShadowBinder; +import org.robolectric.shadows.ShadowBuild; import org.robolectric.shadows.ShadowPackageManager; import java.util.ArrayList; @@ -641,6 +642,7 @@ public class SettingsSliceProviderTest { @Test @Config(qualifiers = "mcc999") public void grantAllowlistedPackagePermissions_hasPackageAllowlist_shouldGrant() { + ShadowBuild.setDebuggable(false); final List uris = new ArrayList<>(); uris.add(Uri.parse("content://settings/slice")); @@ -648,6 +650,23 @@ public class SettingsSliceProviderTest { verify(mManager) .grantSlicePermission("com.android.settings.slice_allowlist_package", uris.get(0)); + verify(mManager, never()) + .grantSlicePermission("com.android.settings.slice_allowlist_package_dev", + uris.get(0)); + } + + @Test + @Config(qualifiers = "mcc999") + public void grantAllowlistedPackagePermissions_hasPackageAllowlistAndDebuggable_shouldGrant() { + ShadowBuild.setDebuggable(true); + final List uris = new ArrayList<>(); + uris.add(Uri.parse("content://settings/slice")); + + SettingsSliceProvider.grantAllowlistedPackagePermissions(mContext, uris); + + verify(mManager) + .grantSlicePermission("com.android.settings.slice_allowlist_package_dev", + uris.get(0)); } @Test -- GitLab From 0db1143041a6f15c4f8ded027d408f5a385e290e Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Tue, 3 Jun 2025 10:46:31 -0400 Subject: [PATCH 2/5] Hide sensistive content from locked profiles Test: manual Flag: EXEMPT bug fix Bug: 396666065 (cherry picked from commit b1bfda5a03c6d21a16da0de2eb77340536400ca6) Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:30c245e3cfdf83dac13adef5813312d7ca27d066 Merged-In: Ie7705a1ceea54203585c3b3737d0bada68aa1469 Change-Id: Ie7705a1ceea54203585c3b3737d0bada68aa1469 --- .../history/NotificationStation.java | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/com/android/settings/notification/history/NotificationStation.java b/src/com/android/settings/notification/history/NotificationStation.java index e79a4ac58c6..4315c6dbfaa 100644 --- a/src/com/android/settings/notification/history/NotificationStation.java +++ b/src/com/android/settings/notification/history/NotificationStation.java @@ -18,10 +18,12 @@ package com.android.settings.notification.history; import static android.provider.Settings.EXTRA_APP_PACKAGE; import static android.provider.Settings.EXTRA_CHANNEL_ID; +import static android.provider.Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS; import android.app.Activity; import android.app.ActivityManager; import android.app.INotificationManager; +import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.PendingIntent; @@ -32,6 +34,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -40,6 +43,7 @@ import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.Ranking; @@ -60,6 +64,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import androidx.recyclerview.widget.RecyclerView; +import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; @@ -117,6 +122,7 @@ public class NotificationStation extends SettingsPreferenceFragment { private INotificationManager mNoMan; private RankingMap mRanking; private LinkedList mNotificationInfos; + private ArrayList mContentRestrictedUsers = new ArrayList<>(); private final NotificationListenerService mListener = new NotificationListenerService() { @Override @@ -208,6 +214,21 @@ public class NotificationStation extends SettingsPreferenceFragment { public void onResume() { logd("onResume()"); super.onResume(); + + mContentRestrictedUsers.clear(); + List users = + getSystemService(UserManager.class).getProfiles(mContext.getUserId()); + for (UserInfo user : users) { + if (Settings.Secure.getIntForUser(getContentResolver(), + LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, user.id) == 0) { + LockPatternUtils lpu = new LockPatternUtils(mContext); + KeyguardManager km = getSystemService(KeyguardManager.class); + if (lpu.isSecure(user.id) && km.isDeviceLocked(user.id)) { + mContentRestrictedUsers.add(user.id); + } + } + } + try { mListener.registerAsSystemService(mContext, new ComponentName(mContext.getPackageName(), this.getClass().getCanonicalName()), ActivityManager.getCurrentUser()); @@ -229,7 +250,8 @@ public class NotificationStation extends SettingsPreferenceFragment { getPreferenceScreen().removeAll(); for (int i = 0; i < N; i++) { getPreferenceScreen().addPreference(new HistoricalNotificationPreference( - getPrefContext(), mNotificationInfos.get(i), i)); + getPrefContext(), mNotificationInfos.get(i), i, + mContentRestrictedUsers.contains(mNotificationInfos.get(i).user))); } } @@ -243,7 +265,8 @@ public class NotificationStation extends SettingsPreferenceFragment { if (TextUtils.equals(info.key, sbn.getKey())) { info.active = false; ((HistoricalNotificationPreference) getPreferenceScreen().findPreference( - sbn.getKey())).updatePreference(info); + sbn.getKey())).updatePreference( + info, mContentRestrictedUsers.contains(info.user)); break; } } @@ -264,7 +287,8 @@ public class NotificationStation extends SettingsPreferenceFragment { info.updateFrom(newInfo); ((HistoricalNotificationPreference) getPreferenceScreen().findPreference( - sbn.getKey())).updatePreference(info); + sbn.getKey())).updatePreference( + info, mContentRestrictedUsers.contains(info.user)); needsAdd = false; break; } @@ -273,7 +297,8 @@ public class NotificationStation extends SettingsPreferenceFragment { mNotificationInfos.addFirst(newInfo); getPreferenceScreen().addPreference(new HistoricalNotificationPreference( getPrefContext(), mNotificationInfos.peekFirst(), - -1 * mNotificationInfos.size())); + -1 * mNotificationInfos.size(), + mContentRestrictedUsers.contains(newInfo.user))); } } @@ -290,7 +315,7 @@ public class NotificationStation extends SettingsPreferenceFragment { updateFromRanking(info); ((HistoricalNotificationPreference) getPreferenceScreen().findPreference( - info.key)).updatePreference(info); + info.key)).updatePreference(info, mContentRestrictedUsers.contains(info.user)); } } @@ -405,6 +430,7 @@ public class NotificationStation extends SettingsPreferenceFragment { private HistoricalNotificationInfo createFromSbn(StatusBarNotification sbn, boolean active) { final Notification n = sbn.getNotification(); final HistoricalNotificationInfo info = new HistoricalNotificationInfo(); + info.pkg = sbn.getPackageName(); info.user = sbn.getUserId() == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : sbn.getUserId(); @@ -416,6 +442,7 @@ public class NotificationStation extends SettingsPreferenceFragment { info.pkgname = loadPackageName(info.pkg); info.title = getTitleString(n); info.text = getTextString(sbn.getPackageContext(mContext), n); + info.timestamp = sbn.getPostTime(); info.priority = n.priority; info.key = sbn.getKey(); @@ -673,15 +700,17 @@ public class NotificationStation extends SettingsPreferenceFragment { private static long sLastExpandedTimestamp; // quick hack to keep things from collapsing public ViewGroup mItemView; // hack to update prefs fast; private Context mContext; + private boolean mRestrictContent; public HistoricalNotificationPreference(Context context, HistoricalNotificationInfo info, - int order) { + int order, boolean restrictContent) { super(context); setLayoutResource(R.layout.notification_log_row); setOrder(order); setKey(info.key); mInfo = info; mContext = context; + mRestrictContent = restrictContent; } @Override @@ -690,7 +719,7 @@ public class NotificationStation extends SettingsPreferenceFragment { mItemView = (ViewGroup) row.itemView; - updatePreference(mInfo); + updatePreference(mInfo, mRestrictContent); row.findViewById(R.id.timestamp).setOnLongClickListener(v -> { final View extras = row.findViewById(R.id.extra); @@ -701,7 +730,7 @@ public class NotificationStation extends SettingsPreferenceFragment { }); } - public void updatePreference(HistoricalNotificationInfo info) { + public void updatePreference(HistoricalNotificationInfo info, boolean restrictContent) { if (mItemView == null) { return; } @@ -710,17 +739,17 @@ public class NotificationStation extends SettingsPreferenceFragment { } ((TextView) mItemView.findViewById(R.id.pkgname)).setText(mInfo.pkgname); ((DateTimeView) mItemView.findViewById(R.id.timestamp)).setTime(info.timestamp); - if (!TextUtils.isEmpty(info.title)) { + if (restrictContent || TextUtils.isEmpty(info.title)) { + mItemView.findViewById(R.id.title).setVisibility(View.GONE); + } else { ((TextView) mItemView.findViewById(R.id.title)).setText(info.title); mItemView.findViewById(R.id.title).setVisibility(View.VISIBLE); - } else { - mItemView.findViewById(R.id.title).setVisibility(View.GONE); } - if (!TextUtils.isEmpty(info.text)) { + if (restrictContent || TextUtils.isEmpty(info.text)) { + mItemView.findViewById(R.id.text).setVisibility(View.GONE); + } else { ((TextView) mItemView.findViewById(R.id.text)).setText(info.text); mItemView.findViewById(R.id.text).setVisibility(View.VISIBLE); - } else { - mItemView.findViewById(R.id.text).setVisibility(View.GONE); } if (info.icon != null) { ((ImageView) mItemView.findViewById(R.id.icon)).setImageDrawable(info.icon); @@ -734,10 +763,15 @@ public class NotificationStation extends SettingsPreferenceFragment { ((DateTimeView) mItemView.findViewById(R.id.timestamp)).setTime(mInfo.timestamp); - ((TextView) mItemView.findViewById(R.id.notification_extra)) - .setText(mInfo.notificationExtra); - ((TextView) mItemView.findViewById(R.id.ranking_extra)) - .setText(mInfo.rankingExtra); + if (restrictContent) { + mItemView.findViewById(R.id.notification_extra).setVisibility(View.GONE); + mItemView.findViewById(R.id.ranking_extra).setVisibility(View.GONE); + } else { + ((TextView) mItemView.findViewById(R.id.notification_extra)) + .setText(mInfo.notificationExtra); + ((TextView) mItemView.findViewById(R.id.ranking_extra)) + .setText(mInfo.rankingExtra); + } mItemView.findViewById(R.id.extra).setVisibility( mInfo.timestamp == sLastExpandedTimestamp ? View.VISIBLE : View.GONE); -- GitLab From adac3d79c0f30b13aadfb75a78eb02fe60945ad6 Mon Sep 17 00:00:00 2001 From: James Eidson Date: Thu, 14 Aug 2025 19:54:00 +0000 Subject: [PATCH 3/5] [nfc] Fix string injection in default payment app selector Backwards compatible port of ag/35084316 Bug: 429417453 Test: Manually by installing settings app Flag: EXEMPT security fix (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:6c723a4361950e8e43cc5caf67455bd2f00911d1) Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:0f4bac3237558bc042802ef917c454d520cbad52 Merged-In: I670774a5efa6f543a5e1e06798a5d6ebb1c48c1d Change-Id: I670774a5efa6f543a5e1e06798a5d6ebb1c48c1d --- .../settings/nfc/DefaultPaymentSettings.java | 29 ++++++++++--------- .../android/settings/nfc/PaymentBackend.java | 19 ++++++++++++ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/nfc/DefaultPaymentSettings.java b/src/com/android/settings/nfc/DefaultPaymentSettings.java index ddac08beb00..440f09e3d9b 100644 --- a/src/com/android/settings/nfc/DefaultPaymentSettings.java +++ b/src/com/android/settings/nfc/DefaultPaymentSettings.java @@ -17,7 +17,6 @@ package com.android.settings.nfc; import android.app.settings.SettingsEnums; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -45,6 +44,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; /** * DefaultPaymentSettings handles the NFC default payment app selection. @@ -53,7 +55,7 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { public static final String TAG = "DefaultPaymentSettings"; private PaymentBackend mPaymentBackend; - private List mAppInfos; + private Map mAppInfos; private FooterPreference mFooterPreference; @Override @@ -67,22 +69,19 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { } @Override + @SuppressWarnings("NullAway") protected String getDefaultKey() { PaymentAppInfo defaultAppInfo = mPaymentBackend.getDefaultApp(); - if (defaultAppInfo != null) { - return defaultAppInfo.componentName.flattenToString() + " " - + defaultAppInfo.userHandle.getIdentifier(); - } - return null; + if (defaultAppInfo == null) return null; + return defaultAppInfo.getKey(); } @Override protected boolean setDefaultKey(String key) { - String[] keys = key.split(" "); - if (keys.length >= 2) { - mPaymentBackend.setDefaultPaymentApp(ComponentName.unflattenFromString(keys[0]), - Integer.parseInt(keys[1])); - } + PaymentAppInfo appInfo = mAppInfos.get(key); + if (appInfo == null) return true; + mPaymentBackend.setDefaultPaymentApp( + appInfo.componentName, appInfo.userHandle.getIdentifier()); return true; } @@ -90,7 +89,9 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { public void onAttach(Context context) { super.onAttach(context); mPaymentBackend = new PaymentBackend(getActivity()); - mAppInfos = mPaymentBackend.getPaymentAppInfos(); + mAppInfos = mPaymentBackend.getPaymentAppInfos() + .stream() + .collect(Collectors.toMap(PaymentAppInfo::getKey, Function.identity())); } @Override @@ -147,7 +148,7 @@ public class DefaultPaymentSettings extends DefaultAppPickerFragment { @Override protected List getCandidates() { final List candidates = new ArrayList<>(); - for (PaymentAppInfo appInfo: mAppInfos) { + for (PaymentAppInfo appInfo: mAppInfos.values()) { UserManager um = getContext().createContextAsUser( appInfo.userHandle, /*flags=*/0).getSystemService(UserManager.class); boolean isManagedProfile = um.isManagedProfile(appInfo.userHandle.getIdentifier()); diff --git a/src/com/android/settings/nfc/PaymentBackend.java b/src/com/android/settings/nfc/PaymentBackend.java index 021d673e152..de733081a1d 100644 --- a/src/com/android/settings/nfc/PaymentBackend.java +++ b/src/com/android/settings/nfc/PaymentBackend.java @@ -36,6 +36,7 @@ import com.android.internal.content.PackageMonitor; import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class PaymentBackend { public static final String TAG = "Settings.PaymentBackend"; @@ -52,6 +53,24 @@ public class PaymentBackend { public ComponentName settingsComponent; public UserHandle userHandle; public Drawable icon; + + public String getKey() { + return Integer.toString(hashCode()); + } + + @Override + public int hashCode() { + return Objects.hash(componentName, userHandle); + } + + @Override + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof PaymentAppInfo)) return false; + PaymentAppInfo appInfo = (PaymentAppInfo) o; + return componentName.equals(appInfo.componentName) + && userHandle.equals(appInfo.userHandle); + } } /** -- GitLab From 6a6a1f7f54a70410d06037d62b63faae7ec3622a Mon Sep 17 00:00:00 2001 From: Haijie Hong Date: Mon, 12 May 2025 13:44:55 +0800 Subject: [PATCH 4/5] Backport BT pairing dialog changes This is a combination of two commits against b/409868905, merged for backport convenience. It updates the string and button style for the BT pairing dialog. Bug: 236134583 Bug: 236134775 Test: local tested Flag: EXEMPT minor style update Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:b2f755f7fe672a5b6d08c1a8cfde99dcb2fb3bbc Merged-In: Icd9f509b5363b3ec3900738e21486e54d4e66e4b Change-Id: Icd9f509b5363b3ec3900738e21486e54d4e66e4b --- res/layout/bluetooth_pin_confirm.xml | 42 ++++++++++- res/layout/bluetooth_pin_entry.xml | 27 ++++++- res/values/strings.xml | 6 ++ .../BluetoothPairingDialogFragment.java | 70 ++++++++++++------- .../bluetooth/BluetoothPairingDialogTest.java | 36 +++++++--- 5 files changed, 144 insertions(+), 37 deletions(-) diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml index fb3435bf342..0fff73d1058 100644 --- a/res/layout/bluetooth_pin_confirm.xml +++ b/res/layout/bluetooth_pin_confirm.xml @@ -19,6 +19,7 @@ @@ -29,6 +30,18 @@ android:layout_marginTop="@dimen/bluetooth_dialog_padding_top" android:orientation="vertical"> + + - + +