Reconcile picks

Signed-off-by: Tavi <tavi@divested.dev>
This commit is contained in:
Tavi 2024-06-16 15:55:36 -04:00
parent 0b746cecf4
commit ba9e22dc77
No known key found for this signature in database
GPG Key ID: E599F62ECBAEAF2E
24 changed files with 474 additions and 2193 deletions

View File

@ -0,0 +1,47 @@
From 00961ad29e26dde5d4f56de90ac333ceb2fc8d34 Mon Sep 17 00:00:00 2001
From: Jing Ji <jji@google.com>
Date: Tue, 25 Oct 2022 22:39:52 -0700
Subject: [PATCH] DO NOT MERGE: ActivityManager#killBackgroundProcesses can
kill caller's own app only
unless it's a system app.
Bug: 239423414
Bug: 223376078
Test: atest CtsAppTestCases:ActivityManagerTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d1c95670b248df945784b0f2830acf83b5682de3)
Merged-In: Iac6baa889965b8ffecd9a43179a4c96632ad1d02
AOSP-Change-Id: Iac6baa889965b8ffecd9a43179a4c96632ad1d02
Change-Id: I41cd6fa1f71e950db18a9fd450355c4e6f80ec7d
---
.../server/am/ActivityManagerService.java | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 234b23a996267..815ddf63e565a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4486,6 +4486,22 @@ void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
throw new SecurityException(msg);
}
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ if (callingUid >= FIRST_APPLICATION_UID
+ && (proc == null || !proc.info.isSystemApp())) {
+ final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
+ + callingPid + ", uid=" + callingUid + " is not allowed";
+ Slog.w(TAG, msg);
+ // Silently return to avoid existing apps from crashing.
+ return;
+ }
+
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (this) {

View File

@ -0,0 +1,46 @@
From 14804676d97278009b746073e8339374b0cce927 Mon Sep 17 00:00:00 2001
From: Jing Ji <jji@google.com>
Date: Thu, 19 Oct 2023 14:22:58 -0700
Subject: [PATCH] DO NOT MERGE: Fix ActivityManager#killBackgroundProcesses
permissions
In the pevious CL, we incorrectly added the permission check in the
killBackgroundProcessesExcept. Now fix this issue.
Bug: 239423414
Bug: 223376078
Test: atest CtsAppTestCases:ActivityManagerTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:140fce861944419a375c669010c6c47cd7ff5b37)
Merged-In: I9471a77188ee63ec32cd0c81569193e4ccad885b
Change-Id: I9471a77188ee63ec32cd0c81569193e4ccad885b
---
.../server/am/ActivityManagerService.java | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 815ddf63e565a..234b23a996267 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4486,22 +4486,6 @@ void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
throw new SecurityException(msg);
}
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
-
- ProcessRecord proc;
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(callingPid);
- }
- if (callingUid >= FIRST_APPLICATION_UID
- && (proc == null || !proc.info.isSystemApp())) {
- final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
- + callingPid + ", uid=" + callingUid + " is not allowed";
- Slog.w(TAG, msg);
- // Silently return to avoid existing apps from crashing.
- return;
- }
-
final long callingId = Binder.clearCallingIdentity();
try {
synchronized (this) {

View File

@ -1,4 +1,4 @@
From c0c16283997bbca63edc79d820652587cbde15bb Mon Sep 17 00:00:00 2001
From 179a5a7b48c4ec3ffebbf53b9833f6be6ef4e2b1 Mon Sep 17 00:00:00 2001
From: Valentin Iftime <valiiftime@google.com>
Date: Thu, 1 Feb 2024 13:58:49 +0100
Subject: [PATCH] Verify URI permission for channel sound update from
@ -10,19 +10,19 @@ Subject: [PATCH] Verify URI permission for channel sound update from
Test: atest com.android.server.notification.NotificationManagerServiceTest#testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission
Bug: 317357401
(cherry picked from commit 9b7bbbf5ad542ecf9ecbf8cd819b468791b443c0)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2f26c0def503d3b8032c99adc8a11be87e35cdeb)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f090c0538a27d8658d8a860046d5c5e931302341)
Merged-In: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
Change-Id: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
---
.../NotificationManagerService.java | 22 +++++++
.../NotificationManagerServiceTest.java | 63 +++++++++++++++++++
2 files changed, 85 insertions(+)
.../NotificationManagerService.java | 22 ++++++
.../NotificationManagerServiceTest.java | 67 +++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ecd446519c09..4d1abc61aa73 100755
index dfc9c135c7da7..40f6ed45174e2 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5705,6 +5705,10 @@ public void updateNotificationChannelFromPrivilegedListener(INotificationListene
@@ -5151,6 +5151,10 @@ public void updateNotificationChannelFromPrivilegedListener(INotificationListene
Objects.requireNonNull(user);
verifyPrivilegedListener(token, user, false);
@ -33,7 +33,7 @@ index ecd446519c09..4d1abc61aa73 100755
updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
}
@@ -5796,6 +5800,24 @@ private void verifyPrivilegedListener(INotificationListener token, UserHandle us
@@ -5230,6 +5234,24 @@ private void verifyPrivilegedListener(INotificationListener token, UserHandle us
}
}
@ -56,13 +56,13 @@ index ecd446519c09..4d1abc61aa73 100755
+ }
+
private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
int uid = INVALID_UID;
final long identity = Binder.clearCallingIdentity();
int uid = 0;
long identity = Binder.clearCallingIdentity();
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 4f0a7ca0ad51..755bc1d35cf3 100755
index 011c408492fa3..a1d6b56ff9cdb 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3319,6 +3319,69 @@ public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws
@@ -2664,6 +2664,73 @@ public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
}
@ -70,8 +70,10 @@ index 4f0a7ca0ad51..755bc1d35cf3 100755
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
+ throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+ List<String> associations = new ArrayList<>();
+ associations.add("a");
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
+ .thenReturn(associations);
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(mTestNotificationChannel);
@ -102,8 +104,10 @@ index 4f0a7ca0ad51..755bc1d35cf3 100755
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
+ throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+ List<String> associations = new ArrayList<>();
+ associations.add("a");
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
+ .thenReturn(associations);
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
+ .thenReturn(mTestNotificationChannel);

View File

@ -0,0 +1,270 @@
From 1ac8480b3163815253b07d5e2ffa5ae3d5065a07 Mon Sep 17 00:00:00 2001
From: Valentin Iftime <valiiftime@google.com>
Date: Thu, 22 Feb 2024 10:51:58 +0100
Subject: [PATCH] Check for NLS bind permission when rebinding services
Also, after updating packages with NLS components, check
the approved services and remove from approved list if missing permissions.
Test: atest ManagedServicesTest
Bug: 321707289
(cherry picked from commit 24b13a64f9f5e5aa7f45a2132806d6c74e2c62dc)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0c15cdfdd4720efb72c3244a044bb27e2c286c4b)
Merged-In: I11901755ec430c6e3145def9d67e4e63cda00806
Change-Id: I11901755ec430c6e3145def9d67e4e63cda00806
---
.../server/notification/ManagedServices.java | 108 ++++++++++++++----
.../notification/ManagedServicesTest.java | 54 +++++++++
2 files changed, 139 insertions(+), 23 deletions(-)
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index a604625460a77..e5686dc3f0759 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -150,7 +150,9 @@ abstract public class ManagedServices {
// List of approved packages or components (by user, then by primary/secondary) that are
// allowed to be bound as managed services. A package or component appearing in this list does
// not mean that we are currently bound to said package/component.
- private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
+
+ @GuardedBy("mApproved")
+ private final ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
// True if approved services are stored in xml, not settings.
private boolean mUseXml;
@@ -761,6 +763,23 @@ protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId)
return false;
}
+ protected boolean isPackageOrComponentAllowedWithPermission(ComponentName component,
+ int userId) {
+ if (!(isPackageOrComponentAllowed(component.flattenToString(), userId)
+ || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
+ return false;
+ }
+ return componentHasBindPermission(component, userId);
+ }
+
+ private boolean componentHasBindPermission(ComponentName component, int userId) {
+ ServiceInfo info = getServiceInfo(component, userId);
+ if (info == null) {
+ return false;
+ }
+ return mConfig.bindPermission.equals(info.permission);
+ }
+
protected boolean isPackageAllowed(String pkg, int userId) {
if (pkg == null) {
return false;
@@ -811,6 +830,7 @@ public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] u
for (int uid : uidList) {
if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
anyServicesInvolved = true;
+ trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
}
}
}
@@ -938,8 +958,7 @@ protected void setComponentState(ComponentName component, boolean enabled) {
for (int i = 0; i < userIds.size(); i++) {
final int userId = userIds.get(i);
if (enabled) {
- if (isPackageOrComponentAllowed(component.flattenToString(), userId)
- || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
+ if (isPackageOrComponentAllowedWithPermission(component, userId)) {
registerServiceLocked(component, userId);
} else {
Slog.d(TAG, component + " no longer has permission to be bound");
@@ -1078,6 +1097,33 @@ private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, S
return removed;
}
+ private void trimApprovedListsForInvalidServices(String packageName, int userId) {
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
+ final ComponentName component = ComponentName.unflattenFromString(
+ approvedPackageOrComponent);
+ if (component != null && !componentHasBindPermission(component, userId)) {
+ approved.removeAt(j);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no bind permission found "
+ + mConfig.bindPermission);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
protected String getPackageName(String packageOrComponent) {
final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
if (component != null) {
@@ -1237,26 +1283,20 @@ private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
final int userId = componentsToBind.keyAt(i);
final Set<ComponentName> add = componentsToBind.get(userId);
for (ComponentName component : add) {
- try {
- ServiceInfo info = mPm.getServiceInfo(component,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
- if (info == null) {
- Slog.w(TAG, "Not binding " + getCaption() + " service " + component
- + ": service not found");
- continue;
- }
- if (!mConfig.bindPermission.equals(info.permission)) {
- Slog.w(TAG, "Not binding " + getCaption() + " service " + component
- + ": it does not require the permission " + mConfig.bindPermission);
- continue;
- }
- Slog.v(TAG,
- "enabling " + getCaption() + " for " + userId + ": " + component);
- registerService(component, userId);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ ServiceInfo info = getServiceInfo(component, userId);
+ if (info == null) {
+ Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ + ": service not found");
+ continue;
}
+ if (!mConfig.bindPermission.equals(info.permission)) {
+ Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ + ": it does not require the permission " + mConfig.bindPermission);
+ continue;
+ }
+ Slog.v(TAG,
+ "enabling " + getCaption() + " for " + userId + ": " + component);
+ registerService(component, userId);
}
}
}
@@ -1270,6 +1310,15 @@ private void registerService(final ComponentName name, final int userid) {
}
}
+ @VisibleForTesting
+ void reregisterService(final ComponentName cn, final int userId) {
+ // If rebinding a package that died, ensure it still has permission
+ // after the rebind delay
+ if (isPackageOrComponentAllowedWithPermission(cn, userId)) {
+ registerService(cn, userId);
+ }
+ }
+
/**
* Inject a system service into the management list.
*/
@@ -1370,7 +1419,7 @@ public void onBindingDied(ComponentName name) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- registerService(name, userid);
+ reregisterService(name, userid);
}
}, ON_BINDING_DIED_REBIND_DELAY_MS);
} else {
@@ -1502,6 +1551,19 @@ private void unbindService(ServiceConnection connection, ComponentName component
}
}
+ private ServiceInfo getServiceInfo(ComponentName component, int userId) {
+ try {
+ return mPm.getServiceInfo(component,
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null;
+ }
+
public class ManagedServiceInfo implements IBinder.DeathRecipient {
public IInterface service;
public ComponentName component;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 99433a6603c91..e7187f393751d 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -27,8 +27,10 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -775,6 +777,58 @@ public void testUpgradeAppBindsNewServices() throws Exception {
}
}
+ @Test
+ public void testUpgradeAppNoPermissionNoRebind() throws Exception {
+ Context context = spy(getContext());
+ doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
+ mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ addExpectedServices(service, packages, 0);
+
+ final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
+ final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
+
+ // Both components are approved initially
+ mExpectedPrimaryComponentNames.clear();
+ mExpectedPrimaryPackages.clear();
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
+ mExpectedSecondaryComponentNames.clear();
+ mExpectedSecondaryPackages.clear();
+
+ loadXml(service);
+
+ //Component package/C1 loses bind permission
+ when(mIpm.getServiceInfo(any(), anyInt(), anyInt())).thenAnswer(
+ (Answer<ServiceInfo>) invocation -> {
+ ComponentName invocationCn = invocation.getArgument(0);
+ if (invocationCn != null) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = invocationCn.getPackageName();
+ serviceInfo.name = invocationCn.getClassName();
+ if (invocationCn.equals(unapprovedComponent)) {
+ serviceInfo.permission = "none";
+ } else {
+ serviceInfo.permission = service.getConfig().bindPermission;
+ }
+ serviceInfo.metaData = null;
+ return serviceInfo;
+ }
+ return null;
+ }
+ );
+
+ // Trigger package update
+ service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
+
+ assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
+ assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
+ }
+
@Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {

View File

@ -1,4 +1,4 @@
From b403e48e6aff45880c2970102555cc77cdcfe322 Mon Sep 17 00:00:00 2001
From 47b5cdfc811916e1bfe36f98b83697a2027fc96c Mon Sep 17 00:00:00 2001
From: Riddle Hsu <riddlehsu@google.com>
Date: Tue, 6 Feb 2024 17:19:37 +0800
Subject: [PATCH] Hide window immediately if itself doesn't run hide animation
@ -21,10 +21,10 @@ Change-Id: Iafc2b2c2a24d8fc8d147354ef2f0b4afeeb510c5
2 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6d6e84f611cf..0ba2f2f2f418 100644
index 7360e3677def6..319b7e88258db 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3296,8 +3296,10 @@ boolean hide(boolean doAnimation, boolean requestAnim) {
@@ -3009,8 +3009,10 @@ boolean hideLw(boolean doAnimation, boolean requestAnim) {
return false;
}
if (doAnimation) {
@ -38,12 +38,12 @@ index 6d6e84f611cf..0ba2f2f2f418 100644
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 219f4415c623..44ae8dde9bde 100644
index 360d73b5bd872..0bf95eca08f89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -227,6 +227,26 @@ public void testIsOnScreen_hiddenByPolicy() {
@@ -205,6 +205,26 @@ public void testIsOnScreen_hiddenByPolicy() {
assertTrue(window.isOnScreen());
window.hide(false /* doAnimation */, false /* requestAnim */);
window.hideLw(false /* doAnimation */);
assertFalse(window.isOnScreen());
+
+ // Verifies that a window without animation can be hidden even if its parent is animating.

View File

@ -1,6 +1,6 @@
From 88ea616cf95aff9169daec33a0a3d93a30b15727 Mon Sep 17 00:00:00 2001
From 80a45f078fcf1b7157535dcbf07d210ac2c7cd82 Mon Sep 17 00:00:00 2001
From: Yi-an Chen <theianchen@google.com>
Date: Wed, 21 Feb 2024 01:56:22 +0000
Date: Tue, 20 Feb 2024 04:34:57 +0000
Subject: [PATCH] Fix error handling for non-dynamic permissions
We only allow removing dynamic permissions. When removePermission() is
@ -10,22 +10,22 @@ should also return early to avoid the removePermission() call.
Test: manual
Bug: 321555066
Fixes: 321711213
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:528a87e90ff9354581d54fd37fbe9f95cccbcdb1)
Merged-In: Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5
Change-Id: Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2b5d63b64b2b8208ccc4f62eac3d8962f981dbf8)
Merged-In: I7336f2fc78804f26e4b2a329870ecdea776595d8
Change-Id: I7336f2fc78804f26e4b2a329870ecdea776595d8
---
.../server/pm/permission/PermissionManagerServiceImpl.java | 1 +
.../android/server/pm/permission/PermissionManagerService.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 5dc7e23c01e2..1ec3403a9d46 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -681,6 +681,7 @@ public void removePermission(String permName) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index f83c3d5145cc7..eb27a13523baf 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -645,6 +645,7 @@ public void removePermission(String permName) {
// TODO: switch this back to SecurityException
Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+ permName);
+ return;
}
mRegistry.removePermission(permName);
}
mSettings.removePermissionLocked(permName);
mPackageManagerInt.writeSettings(false);

View File

@ -1,4 +1,4 @@
From ac134a1b6a0ace6bf43e83d414f6433f3cf40e53 Mon Sep 17 00:00:00 2001
From 18d1359a28cee22491dbe2f8b814ab999348ebfa Mon Sep 17 00:00:00 2001
From: Dmitry Dementyev <dementyev@google.com>
Date: Tue, 26 Mar 2024 10:31:44 -0700
Subject: [PATCH] Add more checkKeyIntent checks to AccountManagerService.
@ -14,10 +14,10 @@ Change-Id: I9e45d758a2320328da5664b6341eafe6f285f297
1 file changed, 10 insertions(+)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1c3564bfdba2..bc13f106ce6e 100644
index 8a9ddda50d63b..37a68d3eec76c 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3561,6 +3561,11 @@ public void onResult(Bundle result) {
@@ -3475,6 +3475,11 @@ public void onResult(Bundle result) {
// Strip auth token from result.
result.remove(AccountManager.KEY_AUTHTOKEN);
@ -29,7 +29,7 @@ index 1c3564bfdba2..bc13f106ce6e 100644
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG,
@@ -5146,6 +5151,11 @@ public void onResult(Bundle result) {
@@ -5052,6 +5057,11 @@ public void onResult(Bundle result) {
} else {
if (mStripAuthTokenFromResult) {
result.remove(AccountManager.KEY_AUTHTOKEN);

View File

@ -1,8 +1,7 @@
From 5dd0b87bc501c83abbe2462d17fcc7f9f3dfab4d Mon Sep 17 00:00:00 2001
From a0059406f6fa6fa600bd6d5fc488de1d3aa956af Mon Sep 17 00:00:00 2001
From: Haoran Zhang <haoranzhang@google.com>
Date: Wed, 13 Mar 2024 17:08:00 +0000
Subject: [PATCH] [DO NOT MERGE][Autofill Framework] Add in check for intent
filter when setting/updating service
Subject: [PATCH] Add in check for intent filter when setting/updating service
For test, I registered two tests around on ABTD. CtsAutoFillServiceTestCases module is passing except three known failures:
@ -10,11 +9,10 @@ Test run link:
- https://android-build.corp.google.com/builds/abtd/run/L33300030002610600
- https://android-build.corp.google.com/builds/abtd/run/L58100030002616607
Bug: b/324874908
Test: atest CtsAutoFillServiceTestCases
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:141d9d050346bfc4673c429382deb1b3d210f6ad)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ee20adb4b4b2065e040167a4354c4fabaf06e35d)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:51d64705ab70788a536c26d4df5e63f0952ec98f)
Merged-In: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
Change-Id: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
---
@ -22,12 +20,12 @@ Change-Id: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
1 file changed, 27 insertions(+)
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 20b2a74f5be5..2cda39d4b065 100644
index 57ffe0498a88e..309f78006d4b6 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -32,8 +32,10 @@
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.PackageManager;
@ -36,7 +34,7 @@ index 20b2a74f5be5..2cda39d4b065 100644
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
import android.metrics.LogMaker;
@@ -239,6 +241,31 @@ protected boolean updateLocked(boolean disabled) {
@@ -235,6 +237,31 @@ protected boolean updateLocked(boolean disabled) {
@Override // from PerUserSystemService
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
throws NameNotFoundException {

View File

@ -1,4 +1,4 @@
From d0df12d2f498f441d87852580a89f8588380d902 Mon Sep 17 00:00:00 2001
From a0d6c266c99cdcdba0ef4674cf6995619f13efa7 Mon Sep 17 00:00:00 2001
From: Hans Boehm <hboehm@google.com>
Date: Tue, 2 Jan 2024 16:53:13 -0800
Subject: [PATCH] Check hidden API exemptions
@ -18,7 +18,7 @@ Change-Id: I83cd60e46407a4a082f9f3c80e937dbd522dbac4
1 file changed, 10 insertions(+)
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index bf2898137967..63bcf5f119e1 100644
index 39038f555044e..4d69f217c5e6a 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -431,6 +431,8 @@ private Process.ProcessStartResult zygoteSendArgsAndGetResult(
@ -30,18 +30,18 @@ index bf2898137967..63bcf5f119e1 100644
}
}
@@ -972,6 +974,14 @@ private boolean maybeSetApiDenylistExemptions(ZygoteState state, boolean sendIfE
@@ -980,6 +982,14 @@ private boolean maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIf
return true;
}
+ for (/* NonNull */ String s : mApiDenylistExemptions) {
+ for (/* NonNull */ String s : mApiBlacklistExemptions) {
+ // indexOf() is intrinsified and faster than contains().
+ if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0 || s.indexOf('\u0000') >= 0) {
+ Slog.e(LOG_TAG, "Failed to set API denylist exemptions: Bad character");
+ mApiDenylistExemptions = Collections.emptyList();
+ mApiBlacklistExemptions = Collections.emptyList();
+ return false;
+ }
+ }
try {
state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
state.mZygoteOutputWriter.newLine();

View File

@ -1,23 +1,23 @@
From e3979baab5718a69f6d58040ba42f67b4fd73d35 Mon Sep 17 00:00:00 2001
From 4e6cea9041b540298c7c0a326107532d19a0d997 Mon Sep 17 00:00:00 2001
From: Ameer Armaly <aarmaly@google.com>
Date: Fri, 8 Mar 2024 19:41:06 +0000
Subject: [PATCH] [RESTRICT AUTOMERGE] AccessibilityManagerService: remove
uninstalled services from enabled list after service update.
Subject: [PATCH] AccessibilityManagerService: remove uninstalled services from
enabled list after service update.
Bug: 326485767
Test: atest AccessibilityEndToEndTest#testUpdateServiceWithoutIntent_disablesService
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:766911c3312573196b33efd1c3c29ccece806846)
Merged-In: I958d58953b300c8093335a22e207baac471ae9f9
Change-Id: I958d58953b300c8093335a22e207baac471ae9f9
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5405514a23edcba0cf30e6ec78189e3f4e7d95cf)
Merged-In: I5e59296fcad68e62b34c74ee5fd80b6ad6b46fa1
Change-Id: I5e59296fcad68e62b34c74ee5fd80b6ad6b46fa1
---
.../AccessibilityManagerService.java | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 3818a884c94a..8271aed181c9 100644
index f9fbda357075d..021ef5567f25a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2161,10 +2161,13 @@ private void updateServicesLocked(AccessibilityUserState userState) {
@@ -1612,10 +1612,13 @@ private void updateServicesLocked(AccessibilityUserState userState) {
boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class)
.isUserUnlockingOrUnlocked(userState.mUserId);
@ -31,10 +31,10 @@ index 3818a884c94a..8271aed181c9 100644
AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName);
@@ -2215,6 +2218,25 @@ this, getTraceManager(), mWindowManagerService,
@@ -1664,6 +1667,25 @@ this, mWindowManagerService, getSystemActionPerformer(),
if (audioManager != null) {
audioManager.setAccessibilityServiceUids(mTempIntArray);
}
mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray);
+ // If any services have been removed, remove them from the enabled list and the touch
+ // exploration granted list.
+ boolean anyServiceRemoved =

View File

@ -1,7 +1,7 @@
From cbf4c6352bf85e4d8289d6bc1135d66c95f0e1e1 Mon Sep 17 00:00:00 2001
From 42515cb6e3148d89efab6fd39537b874a3f29853 Mon Sep 17 00:00:00 2001
From: Guojing Yuan <guojing@google.com>
Date: Thu, 14 Dec 2023 19:30:04 +0000
Subject: [PATCH] [CDM][CMD] Check permissions for CDM shell commands
Subject: [PATCH] Check permissions for CDM shell commands
Override handleShellCommand instead of onShellCommand because
Binder.onShellCommand checks the necessary permissions of the caller.
@ -10,52 +10,52 @@ Bug: 313428840
Test: manually tested CDM shell commands
(cherry picked from commit 1761a0fee9c2cd9787bbb7fbdbe30b4c2b03396e)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1ae3b43c248cdf5ee63311f06acd0ee19d93f0cd)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8d008c61451dba86aa9f14c6bcd661db2cea4856)
Merged-In: I5539b3594feb5544c458c0fd1061b51a0a808900
Change-Id: I5539b3594feb5544c458c0fd1061b51a0a808900
---
.../CompanionDeviceManagerService.java | 20 ++++++++-----------
1 file changed, 8 insertions(+), 12 deletions(-)
.../companion/CompanionDeviceManagerService.java | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 41546d2bdc38..05c29d7e446a 100644
index 91c2abc024304..275f31f1b6eb0 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -75,12 +75,11 @@
import android.os.Handler;
import android.os.Message;
@@ -28,6 +28,7 @@
import static java.util.concurrent.TimeUnit.MINUTES;
import android.annotation.CheckResult;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -52,11 +53,10 @@
import android.os.IDeviceIdleController;
import android.os.IInterface;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.PowerWhitelistManager;
import android.os.RemoteCallbackList;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
import android.os.ServiceManager;
-import android.os.ShellCallback;
import android.os.SystemProperties;
import android.os.ShellCommand;
import android.os.UserHandle;
import android.os.UserManager;
@@ -827,16 +826,13 @@ public boolean canPairWithoutPrompt(String packageName, String macAddress, int u
import android.os.UserManagerInternal;
@@ -455,10 +455,12 @@ private void checkUsesFeature(String pkg, int userId) {
}
@Override
- public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
- String[] args, ShellCallback callback, ResultReceiver resultReceiver)
- throws RemoteException {
- enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
-
- final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand(
- CompanionDeviceManagerService.this,
- mAssociationStore,
- mDevicePresenceMonitor);
- cmd.exec(this, in, out, err, args, callback, resultReceiver);
- new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this,
+ mAssociationStore, mDevicePresenceMonitor)
+ return new ShellCmd()
+ .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
+ err.getFileDescriptor(), args);
}
}
@Override

View File

@ -1,225 +0,0 @@
From 42c9c06f9c0f8d7212284c6555e3ffd25bd4ddbf Mon Sep 17 00:00:00 2001
From: Pinyao Ting <pinyaoting@google.com>
Date: Thu, 30 Nov 2023 23:12:39 +0000
Subject: [PATCH] Added throttle when reporting shortcut usage
Bug: 304290201
Test: manual
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bd88f35c6797b1795d1150af92760531ff73f14f)
Merged-In: I96370cbd4f6a55f894c1a93307e5f82dfd394652
Change-Id: I96370cbd4f6a55f894c1a93307e5f82dfd394652
---
.../android/server/pm/ShortcutPackage.java | 32 +++++++++++
.../android/server/pm/ShortcutService.java | 18 ++----
.../server/pm/ShortcutManagerTest1.java | 55 ++++++++++++++++++-
.../server/pm/ShortcutManagerTest2.java | 2 +
4 files changed, 92 insertions(+), 15 deletions(-)
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 5a662d9f3139..3b3c11e1209d 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -33,6 +33,7 @@
import android.app.appsearch.SearchResults;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.SetSchemaRequest;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -47,6 +48,7 @@
import android.os.Binder;
import android.os.PersistableBundle;
import android.os.StrictMode;
+import android.os.SystemClock;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -160,6 +162,9 @@ class ShortcutPackage extends ShortcutPackageItem {
private static final String KEY_BITMAPS = "bitmaps";
private static final String KEY_BITMAP_BYTES = "bitmapBytes";
+ @VisibleForTesting
+ public static final int REPORT_USAGE_BUFFER_SIZE = 3;
+
private final Executor mExecutor;
/**
@@ -195,6 +200,9 @@ class ShortcutPackage extends ShortcutPackageItem {
private long mLastKnownForegroundElapsedTime;
+ @GuardedBy("mLock")
+ private List<Long> mLastReportedTime = new ArrayList<>();
+
@GuardedBy("mLock")
private boolean mIsAppSearchSchemaUpToDate;
@@ -1677,6 +1685,30 @@ public boolean hasNonManifestShortcuts() {
return condition[0];
}
+ void reportShortcutUsed(@NonNull final UsageStatsManagerInternal usageStatsManagerInternal,
+ @NonNull final String shortcutId) {
+ synchronized (mLock) {
+ final long currentTS = SystemClock.elapsedRealtime();
+ final ShortcutService s = mShortcutUser.mService;
+ if (mLastReportedTime.isEmpty()
+ || mLastReportedTime.size() < REPORT_USAGE_BUFFER_SIZE) {
+ mLastReportedTime.add(currentTS);
+ } else if (currentTS - mLastReportedTime.get(0) > s.mSaveDelayMillis) {
+ mLastReportedTime.remove(0);
+ mLastReportedTime.add(currentTS);
+ } else {
+ return;
+ }
+ final long token = s.injectClearCallingIdentity();
+ try {
+ usageStatsManagerInternal.reportShortcutUsage(getPackageName(), shortcutId,
+ getUser().getUserId());
+ } finally {
+ s.injectRestoreCallingIdentity(token);
+ }
+ }
+ }
+
public void dump(@NonNull PrintWriter pw, @NonNull String prefix, DumpFilter filter) {
pw.println();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 7fd32d2a6b1b..84eb799e31ff 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -365,7 +365,7 @@ public boolean test(PackageInfo pi) {
private CompressFormat mIconPersistFormat;
private int mIconPersistQuality;
- private int mSaveDelayMillis;
+ int mSaveDelayMillis;
private final IPackageManager mIPackageManager;
private final PackageManagerInternal mPackageManagerInternal;
@@ -2269,7 +2269,7 @@ public void pushDynamicShortcut(String packageName, ShortcutInfo shortcut,
packageShortcutsChanged(ps, changedShortcuts, removedShortcuts);
- reportShortcutUsedInternal(packageName, shortcut.getId(), userId);
+ ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcut.getId());
verifyStates();
}
@@ -2676,25 +2676,17 @@ public void reportShortcutUsed(String packageName, String shortcutId, int userId
Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d",
shortcutId, packageName, userId));
}
+ final ShortcutPackage ps;
synchronized (mLock) {
throwIfUserLockedL(userId);
- final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
+ ps = getPackageShortcutsForPublisherLocked(packageName, userId);
if (ps.findShortcutById(shortcutId) == null) {
Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
packageName, shortcutId));
return;
}
}
- reportShortcutUsedInternal(packageName, shortcutId, userId);
- }
-
- private void reportShortcutUsedInternal(String packageName, String shortcutId, int userId) {
- final long token = injectClearCallingIdentity();
- try {
- mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId);
- } finally {
- injectRestoreCallingIdentity(token);
- }
+ ps.reportShortcutUsed(mUsageStatsManagerInternal, shortcutId);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 867890f938ba..0f00fb877afe 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -402,8 +402,8 @@ public void testAddDynamicShortcuts() {
public void testPushDynamicShortcut() {
// Change the max number of shortcuts.
- mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5");
-
+ mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=5,"
+ + ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
setCaller(CALLING_PACKAGE_1, USER_0);
final ShortcutInfo s1 = makeShortcut("s1");
@@ -541,6 +541,57 @@ public void testPushDynamicShortcut() {
eq(CALLING_PACKAGE_1), eq("s9"), eq(USER_0));
}
+ public void testPushDynamicShortcut_CallsToUsageStatsManagerAreThrottled()
+ throws InterruptedException {
+ mService.updateConfigurationLocked(
+ ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=500");
+
+ // Verify calls to UsageStatsManagerInternal#reportShortcutUsage are throttled.
+ setCaller(CALLING_PACKAGE_1, USER_0);
+ for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) {
+ final ShortcutInfo si = makeShortcut("s" + i);
+ mManager.pushDynamicShortcut(si);
+ }
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
+ eq(CALLING_PACKAGE_1), eq("s1"), eq(USER_0));
+ Mockito.reset(mMockUsageStatsManagerInternal);
+ for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) {
+ final ShortcutInfo si = makeShortcut("s" + i);
+ mManager.pushDynamicShortcut(si);
+ }
+ verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
+ any(), any(), anyInt());
+
+ // Verify pkg2 isn't blocked by pkg1, but consecutive calls from pkg2 are throttled as well.
+ setCaller(CALLING_PACKAGE_2, USER_0);
+ for (int i = 0; i < ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i++) {
+ final ShortcutInfo si = makeShortcut("s" + i);
+ mManager.pushDynamicShortcut(si);
+ }
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
+ eq(CALLING_PACKAGE_2), eq("s1"), eq(USER_0));
+ Mockito.reset(mMockUsageStatsManagerInternal);
+ for (int i = ShortcutPackage.REPORT_USAGE_BUFFER_SIZE; i <= 10; i++) {
+ final ShortcutInfo si = makeShortcut("s" + i);
+ mManager.pushDynamicShortcut(si);
+ }
+ verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
+ any(), any(), anyInt());
+
+ Mockito.reset(mMockUsageStatsManagerInternal);
+ // Let time passes which resets the throttle
+ Thread.sleep(505);
+ // Verify UsageStatsManagerInternal#reportShortcutUsed can be called again
+ setCaller(CALLING_PACKAGE_1, USER_0);
+ mManager.pushDynamicShortcut(makeShortcut("s10"));
+ setCaller(CALLING_PACKAGE_2, USER_0);
+ mManager.pushDynamicShortcut(makeShortcut("s10"));
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
+ eq(CALLING_PACKAGE_1), any(), eq(USER_0));
+ verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
+ eq(CALLING_PACKAGE_2), any(), eq(USER_0));
+ }
+
public void testUnlimitedCalls() {
setCaller(CALLING_PACKAGE_1, USER_0);
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 86d4655e9d3a..ea134dc66e3f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -2175,6 +2175,8 @@ public void testThrottling_resetByInternalCall() throws Exception {
public void testReportShortcutUsed() {
mRunningUsers.put(USER_10, true);
+ mService.updateConfigurationLocked(
+ ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
reset(mMockUsageStatsManagerInternal);

View File

@ -1,463 +0,0 @@
From fcb02396749ec9318803887febffea13f726dfc2 Mon Sep 17 00:00:00 2001
From: Valentin Iftime <valiiftime@google.com>
Date: Thu, 22 Feb 2024 10:51:58 +0100
Subject: [PATCH] Check for NLS bind permission when rebinding services
Also, after updating packages with NLS components, check
the approved services and remove from approved list if missing permissions.
Test: atest ManagedServicesTest
Bug: 321707289
(cherry picked from commit 24b13a64f9f5e5aa7f45a2132806d6c74e2c62dc)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f126be35f4b9f179dbb957ec56ca80b12f47abdc)
Merged-In: I11901755ec430c6e3145def9d67e4e63cda00806
Change-Id: I11901755ec430c6e3145def9d67e4e63cda00806
---
.../server/notification/ManagedServices.java | 193 ++++++++++--------
.../notification/ManagedServicesTest.java | 54 +++++
2 files changed, 164 insertions(+), 83 deletions(-)
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index d0cfa164b5af..c3691e717e9b 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -132,7 +132,6 @@ abstract public class ManagedServices {
// contains connections to all connected services, including app services
// and system services
- @GuardedBy("mMutex")
private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
/**
* The services that have been bound by us. If the service is also connected, it will also
@@ -151,15 +150,13 @@ abstract public class ManagedServices {
= new ArraySet<>();
// Just the packages from mEnabledServicesForCurrentProfiles
private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
- // Per user id, list of enabled packages that have nevertheless asked not to be run
- private final android.util.SparseSetArray<ComponentName> mSnoozing =
- new android.util.SparseSetArray<>();
+ // List of enabled packages that have nevertheless asked not to be run
+ private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
// List of approved packages or components (by user, then by primary/secondary) that are
// allowed to be bound as managed services. A package or component appearing in this list does
// not mean that we are currently bound to said package/component.
- protected final ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved =
- new ArrayMap<>();
+ protected ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
// List of packages or components (by user) that are configured to be enabled/disabled
// explicitly by the user
@@ -318,7 +315,6 @@ ArrayMap<Boolean, ArrayList<ComponentName>> resetComponents(String packageName,
return changes;
}
- @GuardedBy("mApproved")
private boolean clearUserSetFlagLocked(ComponentName component, int userId) {
String approvedValue = getApprovedValue(component.flattenToString());
ArraySet<String> userSet = mUserSetServices.get(userId);
@@ -379,8 +375,8 @@ public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" " + cmpt);
}
+ pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
synchronized (mMutex) {
- pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
for (ManagedServiceInfo info : mServices) {
if (filter != null && !filter.matches(info.component)) continue;
pw.println(" " + info.component
@@ -390,15 +386,10 @@ public void dump(PrintWriter pw, DumpFilter filter) {
}
}
- synchronized (mSnoozing) {
- pw.println(" Snoozed " + getCaption() + "s ("
- + mSnoozing.size() + "):");
- for (int i = 0; i < mSnoozing.size(); i++) {
- pw.println(" User: " + mSnoozing.keyAt(i));
- for (ComponentName name : mSnoozing.valuesAt(i)) {
- pw.println(" " + name.flattenToShortString());
- }
- }
+ pw.println(" Snoozed " + getCaption() + "s (" +
+ mSnoozingForCurrentProfiles.size() + "):");
+ for (ComponentName name : mSnoozingForCurrentProfiles) {
+ pw.println(" " + name.flattenToShortString());
}
}
@@ -440,16 +431,8 @@ public void dump(ProtoOutputStream proto, DumpFilter filter) {
}
}
- synchronized (mSnoozing) {
- for (int i = 0; i < mSnoozing.size(); i++) {
- long token = proto.start(ManagedServicesProto.SNOOZED);
- proto.write(ManagedServicesProto.SnoozedServices.USER_ID,
- mSnoozing.keyAt(i));
- for (ComponentName name : mSnoozing.valuesAt(i)) {
- name.dumpDebug(proto, ManagedServicesProto.SnoozedServices.SNOOZED);
- }
- proto.end(token);
- }
+ for (ComponentName name : mSnoozingForCurrentProfiles) {
+ name.dumpDebug(proto, ManagedServicesProto.SNOOZED);
}
}
@@ -918,6 +901,23 @@ protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId)
return false;
}
+ protected boolean isPackageOrComponentAllowedWithPermission(ComponentName component,
+ int userId) {
+ if (!(isPackageOrComponentAllowed(component.flattenToString(), userId)
+ || isPackageOrComponentAllowed(component.getPackageName(), userId))) {
+ return false;
+ }
+ return componentHasBindPermission(component, userId);
+ }
+
+ private boolean componentHasBindPermission(ComponentName component, int userId) {
+ ServiceInfo info = getServiceInfo(component, userId);
+ if (info == null) {
+ return false;
+ }
+ return mConfig.bindPermission.equals(info.permission);
+ }
+
boolean isPackageOrComponentUserSet(String pkgOrComponent, int userId) {
synchronized (mApproved) {
ArraySet<String> services = mUserSetServices.get(userId);
@@ -975,6 +975,7 @@ public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] u
for (int uid : uidList) {
if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
anyServicesInvolved = true;
+ trimApprovedListsForInvalidServices(pkgName, UserHandle.getUserId(uid));
}
}
}
@@ -992,9 +993,6 @@ public void onUserRemoved(int user) {
synchronized (mApproved) {
mApproved.remove(user);
}
- synchronized (mSnoozing) {
- mSnoozing.remove(user);
- }
rebindServices(true, user);
}
@@ -1014,12 +1012,10 @@ private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
return null;
}
final IBinder token = service.asBinder();
- synchronized (mMutex) {
- final int nServices = mServices.size();
- for (int i = 0; i < nServices; i++) {
- final ManagedServiceInfo info = mServices.get(i);
- if (info.service.asBinder() == token) return info;
- }
+ final int N = mServices.size();
+ for (int i = 0; i < N; i++) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (info.service.asBinder() == token) return info;
}
return null;
}
@@ -1094,17 +1090,15 @@ protected void registerGuestService(ManagedServiceInfo guest) {
}
protected void setComponentState(ComponentName component, int userId, boolean enabled) {
- synchronized (mSnoozing) {
- boolean previous = !mSnoozing.contains(userId, component);
- if (previous == enabled) {
- return;
- }
+ boolean previous = !mSnoozingForCurrentProfiles.contains(component);
+ if (previous == enabled) {
+ return;
+ }
- if (enabled) {
- mSnoozing.remove(userId, component);
- } else {
- mSnoozing.add(userId, component);
- }
+ if (enabled) {
+ mSnoozingForCurrentProfiles.remove(component);
+ } else {
+ mSnoozingForCurrentProfiles.add(component);
}
// State changed
@@ -1113,8 +1107,7 @@ protected void setComponentState(ComponentName component, int userId, boolean en
synchronized (mMutex) {
if (enabled) {
- if (isPackageOrComponentAllowed(component.flattenToString(), userId)
- || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
+ if (isPackageOrComponentAllowedWithPermission(component, userId)) {
registerServiceLocked(component, userId);
} else {
Slog.d(TAG, component + " no longer has permission to be bound");
@@ -1252,6 +1245,33 @@ private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, S
return removed;
}
+ private void trimApprovedListsForInvalidServices(String packageName, int userId) {
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (TextUtils.equals(getPackageName(approvedPackageOrComponent), packageName)) {
+ final ComponentName component = ComponentName.unflattenFromString(
+ approvedPackageOrComponent);
+ if (component != null && !componentHasBindPermission(component, userId)) {
+ approved.removeAt(j);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no bind permission found "
+ + mConfig.bindPermission);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
protected String getPackageName(String packageOrComponent) {
final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
if (component != null) {
@@ -1317,10 +1337,7 @@ protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componen
}
final Set<ComponentName> add = new HashSet<>(userComponents);
- ArraySet<ComponentName> snoozed = mSnoozing.get(userId);
- if (snoozed != null) {
- add.removeAll(snoozed);
- }
+ add.removeAll(mSnoozingForCurrentProfiles);
componentsToBind.put(userId, add);
@@ -1438,28 +1455,20 @@ private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
final int userId = componentsToBind.keyAt(i);
final Set<ComponentName> add = componentsToBind.get(userId);
for (ComponentName component : add) {
- try {
- ServiceInfo info = mPm.getServiceInfo(component,
- PackageManager.GET_META_DATA
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- userId);
- if (info == null) {
- Slog.w(TAG, "Not binding " + getCaption() + " service " + component
- + ": service not found");
- continue;
- }
- if (!mConfig.bindPermission.equals(info.permission)) {
- Slog.w(TAG, "Not binding " + getCaption() + " service " + component
- + ": it does not require the permission " + mConfig.bindPermission);
- continue;
- }
- Slog.v(TAG,
- "enabling " + getCaption() + " for " + userId + ": " + component);
- registerService(info, userId);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
+ ServiceInfo info = getServiceInfo(component, userId);
+ if (info == null) {
+ Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ + ": service not found");
+ continue;
}
+ if (!mConfig.bindPermission.equals(info.permission)) {
+ Slog.w(TAG, "Not binding " + getCaption() + " service " + component
+ + ": it does not require the permission " + mConfig.bindPermission);
+ continue;
+ }
+ Slog.v(TAG,
+ "enabling " + getCaption() + " for " + userId + ": " + component);
+ registerService(info, userId);
}
}
}
@@ -1484,8 +1493,7 @@ void registerService(final ComponentName cn, final int userId) {
void reregisterService(final ComponentName cn, final int userId) {
// If rebinding a package that died, ensure it still has permission
// after the rebind delay
- if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
- || isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
+ if (isPackageOrComponentAllowedWithPermission(cn, userId)) {
registerService(cn, userId);
}
}
@@ -1499,12 +1507,10 @@ public void registerSystemService(final ComponentName name, final int userid) {
}
}
- @GuardedBy("mMutex")
private void registerServiceLocked(final ComponentName name, final int userid) {
registerServiceLocked(name, userid, false /* isSystem */);
}
- @GuardedBy("mMutex")
private void registerServiceLocked(final ComponentName name, final int userid,
final boolean isSystem) {
if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
@@ -1590,9 +1596,12 @@ public void onBindingDied(ComponentName name) {
unbindService(this, name, userid);
if (!mServicesRebinding.contains(servicesBindingTag)) {
mServicesRebinding.add(servicesBindingTag);
- mHandler.postDelayed(() ->
- reregisterService(name, userid),
- ON_BINDING_DIED_REBIND_DELAY_MS);
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ reregisterService(name, userid);
+ }
+ }, ON_BINDING_DIED_REBIND_DELAY_MS);
} else {
Slog.v(TAG, getCaption() + " not rebinding in user " + userid
+ " as a previous rebind attempt was made: " + name);
@@ -1635,7 +1644,6 @@ private void unregisterService(ComponentName name, int userid) {
}
}
- @GuardedBy("mMutex")
private void unregisterServiceLocked(ComponentName name, int userid) {
final int N = mServices.size();
for (int i = N - 1; i >= 0; i--) {
@@ -1670,7 +1678,6 @@ private ManagedServiceInfo removeServiceImpl(IInterface service, final int useri
return serviceInfo;
}
- @GuardedBy("mMutex")
private ManagedServiceInfo removeServiceLocked(int i) {
final ManagedServiceInfo info = mServices.remove(i);
onServiceRemovedLocked(info);
@@ -1724,6 +1731,19 @@ private void unbindService(ServiceConnection connection, ComponentName component
}
}
+ private ServiceInfo getServiceInfo(ComponentName component, int userId) {
+ try {
+ return mPm.getServiceInfo(component,
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null;
+ }
+
public class ManagedServiceInfo implements IBinder.DeathRecipient {
public IInterface service;
public ComponentName component;
@@ -1823,7 +1843,7 @@ public boolean isEnabledForCurrentProfiles() {
* from receiving events from the profile.
*/
public boolean isPermittedForProfile(int userId) {
- if (!mUserProfiles.isProfileUser(userId)) {
+ if (!mUserProfiles.isManagedProfile(userId)) {
return true;
}
DevicePolicyManager dpm =
@@ -1899,6 +1919,13 @@ public boolean isCurrentProfile(int userId) {
}
}
+ public boolean isManagedProfile(int userId) {
+ synchronized (mCurrentProfiles) {
+ UserInfo user = mCurrentProfiles.get(userId);
+ return user != null && user.isManagedProfile();
+ }
+ }
+
public boolean isProfileUser(int userId) {
synchronized (mCurrentProfiles) {
UserInfo user = mCurrentProfiles.get(userId);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 8b1384ed894f..7c7bb509ebb4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -33,8 +33,10 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -1117,6 +1119,58 @@ public void testUpgradeAppBindsNewServices() throws Exception {
}
}
+ @Test
+ public void testUpgradeAppNoPermissionNoRebind() throws Exception {
+ Context context = spy(getContext());
+ doReturn(true).when(context).bindServiceAsUser(any(), any(), anyInt(), any());
+
+ ManagedServices service = new TestManagedServices(context, mLock, mUserProfiles,
+ mIpm,
+ APPROVAL_BY_COMPONENT);
+
+ List<String> packages = new ArrayList<>();
+ packages.add("package");
+ addExpectedServices(service, packages, 0);
+
+ final ComponentName unapprovedComponent = ComponentName.unflattenFromString("package/C1");
+ final ComponentName approvedComponent = ComponentName.unflattenFromString("package/C2");
+
+ // Both components are approved initially
+ mExpectedPrimaryComponentNames.clear();
+ mExpectedPrimaryPackages.clear();
+ mExpectedPrimaryComponentNames.put(0, "package/C1:package/C2");
+ mExpectedSecondaryComponentNames.clear();
+ mExpectedSecondaryPackages.clear();
+
+ loadXml(service);
+
+ //Component package/C1 loses bind permission
+ when(mIpm.getServiceInfo(any(), anyLong(), anyInt())).thenAnswer(
+ (Answer<ServiceInfo>) invocation -> {
+ ComponentName invocationCn = invocation.getArgument(0);
+ if (invocationCn != null) {
+ ServiceInfo serviceInfo = new ServiceInfo();
+ serviceInfo.packageName = invocationCn.getPackageName();
+ serviceInfo.name = invocationCn.getClassName();
+ if (invocationCn.equals(unapprovedComponent)) {
+ serviceInfo.permission = "none";
+ } else {
+ serviceInfo.permission = service.getConfig().bindPermission;
+ }
+ serviceInfo.metaData = null;
+ return serviceInfo;
+ }
+ return null;
+ }
+ );
+
+ // Trigger package update
+ service.onPackagesChanged(false, new String[]{"package"}, new int[]{0});
+
+ assertFalse(service.isComponentEnabledForCurrentProfiles(unapprovedComponent));
+ assertTrue(service.isComponentEnabledForCurrentProfiles(approvedComponent));
+ }
+
@Test
public void testSetPackageOrComponentEnabled() throws Exception {
for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {

View File

@ -1,71 +0,0 @@
From 091715c8307fed95ba63870f0c54e74208a78332 Mon Sep 17 00:00:00 2001
From: Lokesh Kumar Goel <lokeshgoel@google.com>
Date: Tue, 27 Feb 2024 23:05:05 +0000
Subject: [PATCH] Fix vulnerability in AttributionSource due to incorrect
Binder call
AttributionSource uses Binder.getCallingUid to verify the UID of the
caller from another process. However, getCallingUid does not always
behave as expected. If the AttributionSource is unparceled outside a
transaction thread, which is quite possible, getCallingUid will return
the UID of the current process instead. If this is a system process,
the UID check gets bypassed entirely, meaning any uid can be provided.
This patch fixes the vulnerability by emptying out the state of the
AttributionSource, so that the service checking its credentials will
fail to give permission to the app.
Bug: 267231571
Test: v2/android-virtual-infra/test_mapping/presubmit-avd
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5d79e535b9a802680062545e15fc1faaf779c0bf)
Merged-In: I3f228064fbd62e1c907f1ebe870cb61102f788f0
Change-Id: I3f228064fbd62e1c907f1ebe870cb61102f788f0
---
.../android/content/AttributionSource.java | 20 ++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 3f2fa2188d24..16b18c85e790 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -31,6 +31,7 @@
import android.os.Process;
import android.permission.PermissionManager;
import android.util.ArraySet;
+import android.util.Log;
import com.android.internal.annotations.Immutable;
@@ -87,6 +88,8 @@
*/
@Immutable
public final class AttributionSource implements Parcelable {
+ private static final String TAG = "AttributionSource";
+
private static final String DESCRIPTOR = "android.content.AttributionSource";
private static final Binder sDefaultToken = new Binder(DESCRIPTOR);
@@ -154,9 +157,20 @@ public AttributionSource(@NonNull AttributionSource current, @Nullable Attributi
AttributionSource(@NonNull Parcel in) {
this(AttributionSourceState.CREATOR.createFromParcel(in));
- // Since we just unpacked this object as part of it transiting a Binder
- // call, this is the perfect time to enforce that its UID and PID can be trusted
- enforceCallingUidAndPid();
+ if (!Binder.isDirectlyHandlingTransaction()) {
+ Log.e(TAG, "Unable to verify calling UID #" + mAttributionSourceState.uid + " PID #"
+ + mAttributionSourceState.pid + " when not handling Binder transaction; "
+ + "clearing.");
+ mAttributionSourceState.pid = -1;
+ mAttributionSourceState.uid = -1;
+ mAttributionSourceState.packageName = null;
+ mAttributionSourceState.attributionTag = null;
+ mAttributionSourceState.next = null;
+ } else {
+ // Since we just unpacked this object as part of it transiting a Binder
+ // call, this is the perfect time to enforce that its UID and PID can be trusted
+ enforceCallingUidAndPid();
+ }
}
/** @hide */

View File

@ -1,912 +0,0 @@
From d444b292de11e14d41a5ce1897cd32360d065671 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= <matiashe@google.com>
Date: Fri, 22 Mar 2024 14:26:23 +0100
Subject: [PATCH] Resolve message/conversation image Uris with the correct user
id
Bug: 317503801
Test: atest ExpandableNotificationRowTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:83975c515773d345c64cadac1cd639ae5c4a8397)
Merged-In: I11c5b39f2d9d8f0788acab43640a6d4abcd5a179
Change-Id: I11c5b39f2d9d8f0788acab43640a6d4abcd5a179
---
.../row/ExpandableNotificationRow.java | 13 +-
.../row/NotificationInlineImageResolver.java | 7 +-
.../row/ExpandableNotificationRowTest.java | 554 +++++-------------
.../systemui/SysuiTestableContext.java | 22 +
4 files changed, 194 insertions(+), 402 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 11598e0c1f51..1cec84a5b02d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -45,6 +45,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.Trace;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -1669,8 +1670,6 @@ void logSkipAttachingKeepInParentChild(
*/
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
- mImageResolver = new NotificationInlineImageResolver(context,
- new NotificationInlineImageCache());
float radius = getResources().getDimension(R.dimen.notification_corner_radius_small);
mSmallRoundness = radius / getMaxRadius();
initDimens();
@@ -1706,6 +1705,8 @@ public void initialize(
FeatureFlags featureFlags,
IStatusBarService statusBarService) {
mEntry = entry;
+ mImageResolver = new NotificationInlineImageResolver(userContextForEntry(mContext, entry),
+ new NotificationInlineImageCache());
mAppName = appName;
if (mMenuRow == null) {
mMenuRow = new NotificationMenuRow(mContext, peopleNotificationIdentifier);
@@ -1743,6 +1744,14 @@ public void initialize(
mFeatureFlags = featureFlags;
}
+ private static Context userContextForEntry(Context base, NotificationEntry entry) {
+ if (base.getUserId() == entry.getSbn().getNormalizedUserId()) {
+ return base;
+ }
+ return base.createContextAsUser(
+ UserHandle.of(entry.getSbn().getNormalizedUserId()), /* flags= */ 0);
+ }
+
private void initDimens() {
mMaxSmallHeightBeforeN = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height_legacy);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index c620f448b3b7..3e932aa616b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -66,7 +66,7 @@ public class NotificationInlineImageResolver implements ImageResolver {
* @param imageCache The implementation of internal cache.
*/
public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
- mContext = context.getApplicationContext();
+ mContext = context;
mImageCache = imageCache;
if (mImageCache != null) {
@@ -76,6 +76,11 @@ public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
updateMaxImageSizes();
}
+ @VisibleForTesting
+ public Context getContext() {
+ return mContext;
+ }
+
/**
* Check if this resolver has its internal cache implementation.
* @return True if has its internal cache, false otherwise.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 957b0f10ec1f..67aae77eee36 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -23,11 +23,14 @@
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL;
+import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.PKG;
+import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.USER_HANDLE;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -38,37 +41,29 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.NotificationChannel;
-import android.graphics.Color;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.graphics.drawable.AnimationDrawable;
-import android.graphics.drawable.Drawable;
+import android.content.Context;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import android.util.DisplayMetrics;
import android.view.View;
-import android.widget.ImageView;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
-import com.android.internal.widget.CachingIconView;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
+import com.android.systemui.SysuiTestableContext;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
import com.android.systemui.statusbar.notification.FeedbackIcon;
-import com.android.systemui.statusbar.notification.SourceType;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
-import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
import org.junit.Assert;
@@ -80,16 +75,20 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.Arrays;
import java.util.List;
-import java.util.function.Consumer;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class ExpandableNotificationRowTest extends SysuiTestCase {
+ private ExpandableNotificationRow mGroupRow;
+ private ExpandableNotificationRow mNotifRow;
+ private ExpandableNotificationRow mPublicRow;
+
private NotificationTestHelper mNotificationTestHelper;
+ boolean mHeadsUpAnimatingAway = false;
+
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Before
@@ -100,109 +99,87 @@ public void setUp() throws Exception {
mDependency,
TestableLooper.get(this));
mNotificationTestHelper.setDefaultInflationFlags(FLAG_CONTENT_VIEW_ALL);
+ // create a standard private notification row
+ Notification normalNotif = mNotificationTestHelper.createNotification();
+ normalNotif.publicVersion = null;
+ mNotifRow = mNotificationTestHelper.createRow(normalNotif);
+ // create a notification row whose public version is identical
+ Notification publicNotif = mNotificationTestHelper.createNotification();
+ publicNotif.publicVersion = mNotificationTestHelper.createNotification();
+ mPublicRow = mNotificationTestHelper.createRow(publicNotif);
+ // create a group row
+ mGroupRow = mNotificationTestHelper.createGroup();
+ mGroupRow.setHeadsUpAnimatingAwayListener(
+ animatingAway -> mHeadsUpAnimatingAway = animatingAway);
- FakeFeatureFlags fakeFeatureFlags = new FakeFeatureFlags();
- fakeFeatureFlags.set(Flags.NOTIFICATION_ANIMATE_BIG_PICTURE, true);
- fakeFeatureFlags.set(Flags.SENSITIVE_REVEAL_ANIM, false);
- mNotificationTestHelper.setFeatureFlags(fakeFeatureFlags);
- }
-
- @Test
- public void testUpdateBackgroundColors_isRecursive() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- group.setTintColor(Color.RED);
- group.getChildNotificationAt(0).setTintColor(Color.GREEN);
- group.getChildNotificationAt(1).setTintColor(Color.BLUE);
-
- assertThat(group.getCurrentBackgroundTint()).isEqualTo(Color.RED);
- assertThat(group.getChildNotificationAt(0).getCurrentBackgroundTint())
- .isEqualTo(Color.GREEN);
- assertThat(group.getChildNotificationAt(1).getCurrentBackgroundTint())
- .isEqualTo(Color.BLUE);
-
- group.updateBackgroundColors();
-
- int resetTint = group.getCurrentBackgroundTint();
- assertThat(resetTint).isNotEqualTo(Color.RED);
- assertThat(group.getChildNotificationAt(0).getCurrentBackgroundTint())
- .isEqualTo(resetTint);
- assertThat(group.getChildNotificationAt(1).getCurrentBackgroundTint())
- .isEqualTo(resetTint);
}
@Test
- public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws Exception {
+ public void testSetSensitiveOnNotifRowNotifiesOfHeightChange() throws InterruptedException {
// GIVEN a sensitive notification row that's currently redacted
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- measureAndLayout(row);
- row.setHideSensitiveForIntrinsicHeight(true);
- row.setSensitive(true, true);
- assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPublicLayout());
- assertThat(row.getIntrinsicHeight()).isGreaterThan(0);
+ measureAndLayout(mNotifRow);
+ mNotifRow.setHideSensitiveForIntrinsicHeight(true);
+ mNotifRow.setSensitive(true, true);
+ assertThat(mNotifRow.getShowingLayout()).isSameInstanceAs(mNotifRow.getPublicLayout());
+ assertThat(mNotifRow.getIntrinsicHeight()).isGreaterThan(0);
// GIVEN that the row has a height change listener
OnHeightChangedListener listener = mock(OnHeightChangedListener.class);
- row.setOnHeightChangedListener(listener);
+ mNotifRow.setOnHeightChangedListener(listener);
// WHEN the row is set to no longer be sensitive
- row.setSensitive(false, true);
+ mNotifRow.setSensitive(false, true);
// VERIFY that the height change listener is invoked
- assertThat(row.getShowingLayout()).isSameInstanceAs(row.getPrivateLayout());
- assertThat(row.getIntrinsicHeight()).isGreaterThan(0);
- verify(listener).onHeightChanged(eq(row), eq(false));
+ assertThat(mNotifRow.getShowingLayout()).isSameInstanceAs(mNotifRow.getPrivateLayout());
+ assertThat(mNotifRow.getIntrinsicHeight()).isGreaterThan(0);
+ verify(listener).onHeightChanged(eq(mNotifRow), eq(false));
}
@Test
- public void testSetSensitiveOnGroupRowNotifiesOfHeightChange() throws Exception {
+ public void testSetSensitiveOnGroupRowNotifiesOfHeightChange() {
// GIVEN a sensitive group row that's currently redacted
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- measureAndLayout(group);
- group.setHideSensitiveForIntrinsicHeight(true);
- group.setSensitive(true, true);
- assertThat(group.getShowingLayout()).isSameInstanceAs(group.getPublicLayout());
- assertThat(group.getIntrinsicHeight()).isGreaterThan(0);
+ measureAndLayout(mGroupRow);
+ mGroupRow.setHideSensitiveForIntrinsicHeight(true);
+ mGroupRow.setSensitive(true, true);
+ assertThat(mGroupRow.getShowingLayout()).isSameInstanceAs(mGroupRow.getPublicLayout());
+ assertThat(mGroupRow.getIntrinsicHeight()).isGreaterThan(0);
// GIVEN that the row has a height change listener
OnHeightChangedListener listener = mock(OnHeightChangedListener.class);
- group.setOnHeightChangedListener(listener);
+ mGroupRow.setOnHeightChangedListener(listener);
// WHEN the row is set to no longer be sensitive
- group.setSensitive(false, true);
+ mGroupRow.setSensitive(false, true);
// VERIFY that the height change listener is invoked
- assertThat(group.getShowingLayout()).isSameInstanceAs(group.getPrivateLayout());
- assertThat(group.getIntrinsicHeight()).isGreaterThan(0);
- verify(listener).onHeightChanged(eq(group), eq(false));
+ assertThat(mGroupRow.getShowingLayout()).isSameInstanceAs(mGroupRow.getPrivateLayout());
+ assertThat(mGroupRow.getIntrinsicHeight()).isGreaterThan(0);
+ verify(listener).onHeightChanged(eq(mGroupRow), eq(false));
}
@Test
- public void testSetSensitiveOnPublicRowDoesNotNotifyOfHeightChange() throws Exception {
- // create a notification row whose public version is identical
- Notification publicNotif = mNotificationTestHelper.createNotification();
- publicNotif.publicVersion = mNotificationTestHelper.createNotification();
- ExpandableNotificationRow publicRow = mNotificationTestHelper.createRow(publicNotif);
-
+ public void testSetSensitiveOnPublicRowDoesNotNotifyOfHeightChange() {
// GIVEN a sensitive public row that's currently redacted
- measureAndLayout(publicRow);
- publicRow.setHideSensitiveForIntrinsicHeight(true);
- publicRow.setSensitive(true, true);
- assertThat(publicRow.getShowingLayout()).isSameInstanceAs(publicRow.getPublicLayout());
- assertThat(publicRow.getIntrinsicHeight()).isGreaterThan(0);
+ measureAndLayout(mPublicRow);
+ mPublicRow.setHideSensitiveForIntrinsicHeight(true);
+ mPublicRow.setSensitive(true, true);
+ assertThat(mPublicRow.getShowingLayout()).isSameInstanceAs(mPublicRow.getPublicLayout());
+ assertThat(mPublicRow.getIntrinsicHeight()).isGreaterThan(0);
// GIVEN that the row has a height change listener
OnHeightChangedListener listener = mock(OnHeightChangedListener.class);
- publicRow.setOnHeightChangedListener(listener);
+ mPublicRow.setOnHeightChangedListener(listener);
// WHEN the row is set to no longer be sensitive
- publicRow.setSensitive(false, true);
+ mPublicRow.setSensitive(false, true);
// VERIFY that the height change listener is not invoked, because the height didn't change
- assertThat(publicRow.getShowingLayout()).isSameInstanceAs(publicRow.getPrivateLayout());
- assertThat(publicRow.getIntrinsicHeight()).isGreaterThan(0);
- assertThat(publicRow.getPrivateLayout().getMinHeight())
- .isEqualTo(publicRow.getPublicLayout().getMinHeight());
- verify(listener, never()).onHeightChanged(eq(publicRow), eq(false));
+ assertThat(mPublicRow.getShowingLayout()).isSameInstanceAs(mPublicRow.getPrivateLayout());
+ assertThat(mPublicRow.getIntrinsicHeight()).isGreaterThan(0);
+ assertThat(mPublicRow.getPrivateLayout().getMinHeight())
+ .isEqualTo(mPublicRow.getPublicLayout().getMinHeight());
+ verify(listener, never()).onHeightChanged(eq(mPublicRow), eq(false));
}
private void measureAndLayout(ExpandableNotificationRow row) {
@@ -219,44 +196,39 @@ private void measureAndLayout(ExpandableNotificationRow row) {
}
@Test
- public void testGroupSummaryNotShowingIconWhenPublic() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
- group.setSensitive(true, true);
- group.setHideSensitiveForIntrinsicHeight(true);
- assertTrue(group.isSummaryWithChildren());
- assertFalse(group.isShowingIcon());
+ public void testGroupSummaryNotShowingIconWhenPublic() {
+ mGroupRow.setSensitive(true, true);
+ mGroupRow.setHideSensitiveForIntrinsicHeight(true);
+ assertTrue(mGroupRow.isSummaryWithChildren());
+ assertFalse(mGroupRow.isShowingIcon());
}
@Test
- public void testNotificationHeaderVisibleWhenAnimating() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
- group.setSensitive(true, true);
- group.setHideSensitive(true, false, 0, 0);
- group.setHideSensitive(false, true, 0, 0);
- assertEquals(View.VISIBLE, group.getChildrenContainer().getVisibleWrapper()
+ public void testNotificationHeaderVisibleWhenAnimating() {
+ mGroupRow.setSensitive(true, true);
+ mGroupRow.setHideSensitive(true, false, 0, 0);
+ mGroupRow.setHideSensitive(false, true, 0, 0);
+ assertEquals(View.VISIBLE, mGroupRow.getChildrenContainer().getVisibleWrapper()
.getNotificationHeader().getVisibility());
}
@Test
- public void testUserLockedResetEvenWhenNoChildren() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
- group.setUserLocked(true);
- group.setUserLocked(false);
+ public void testUserLockedResetEvenWhenNoChildren() {
+ mGroupRow.setUserLocked(true);
+ mGroupRow.removeAllChildren();
+ mGroupRow.setUserLocked(false);
assertFalse("The childrencontainer should not be userlocked but is, the state "
- + "seems out of sync.", group.getChildrenContainer().isUserLocked());
+ + "seems out of sync.", mGroupRow.getChildrenContainer().isUserLocked());
}
@Test
- public void testReinflatedOnDensityChange() throws Exception {
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ public void testReinflatedOnDensityChange() {
+ mGroupRow.setUserLocked(true);
+ mGroupRow.removeAllChildren();
+ mGroupRow.setUserLocked(false);
NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
- row.setChildrenContainer(mockContainer);
-
- row.onDensityOrFontScaleChanged();
-
+ mGroupRow.setChildrenContainer(mockContainer);
+ mGroupRow.onDensityOrFontScaleChanged();
verify(mockContainer).reInflateViews(any(), any());
}
@@ -269,6 +241,17 @@ public void testIconColorShouldBeUpdatedWhenSensitive() throws Exception {
verify(row).updateShelfIconColor();
}
+ @Test
+ public void setNeedsRedactionFreesViewWhenFalse() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(FLAG_CONTENT_VIEW_ALL);
+ row.setNeedsRedaction(true);
+ row.getPublicLayout().setVisibility(View.GONE);
+
+ row.setNeedsRedaction(false);
+ TestableLooper.get(this).processAllMessages();
+ assertNull(row.getPublicLayout().getContractedChild());
+ }
+
@Test
public void testAboveShelfChangedListenerCalled() throws Exception {
ExpandableNotificationRow row = mNotificationTestHelper.createRow();
@@ -298,73 +281,64 @@ public void testAboveShelfChangedListenerCalledHeadsUpGoingAway() throws Excepti
@Test
public void testAboveShelfChangedListenerCalledWhenGoingBelow() throws Exception {
ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+ row.setHeadsUp(true);
AboveShelfChangedListener listener = mock(AboveShelfChangedListener.class);
row.setAboveShelfChangedListener(listener);
- Mockito.reset(listener);
- row.setHeadsUp(true);
row.setAboveShelf(false);
verify(listener).onAboveShelfStateChanged(false);
}
@Test
public void testClickSound() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
- assertTrue("Should play sounds by default.", group.isSoundEffectsEnabled());
+ assertTrue("Should play sounds by default.", mGroupRow.isSoundEffectsEnabled());
StatusBarStateController mock = mNotificationTestHelper.getStatusBarStateController();
when(mock.isDozing()).thenReturn(true);
- group.setSecureStateProvider(()-> false);
+ mGroupRow.setSecureStateProvider(()-> false);
assertFalse("Shouldn't play sounds when dark and trusted.",
- group.isSoundEffectsEnabled());
- group.setSecureStateProvider(()-> true);
+ mGroupRow.isSoundEffectsEnabled());
+ mGroupRow.setSecureStateProvider(()-> true);
assertTrue("Should always play sounds when not trusted.",
- group.isSoundEffectsEnabled());
+ mGroupRow.isSoundEffectsEnabled());
}
@Test
- public void testSetDismissed_longPressListenerRemoved() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
+ public void testSetDismissed_longPressListenerRemoved() {
ExpandableNotificationRow.LongPressListener listener =
mock(ExpandableNotificationRow.LongPressListener.class);
- group.setLongPressListener(listener);
- group.doLongClickCallback(0, 0);
- verify(listener, times(1)).onLongPress(eq(group), eq(0), eq(0),
+ mGroupRow.setLongPressListener(listener);
+ mGroupRow.doLongClickCallback(0,0);
+ verify(listener, times(1)).onLongPress(eq(mGroupRow), eq(0), eq(0),
any(NotificationMenuRowPlugin.MenuItem.class));
reset(listener);
- group.dismiss(true);
- group.doLongClickCallback(0, 0);
- verify(listener, times(0)).onLongPress(eq(group), eq(0), eq(0),
+ mGroupRow.dismiss(true);
+ mGroupRow.doLongClickCallback(0,0);
+ verify(listener, times(0)).onLongPress(eq(mGroupRow), eq(0), eq(0),
any(NotificationMenuRowPlugin.MenuItem.class));
}
@Test
- public void testFeedback_noHeader() throws Exception {
- ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
-
+ public void testFeedback_noHeader() {
// public notification is custom layout - no header
- groupRow.setSensitive(true, true);
- groupRow.setOnFeedbackClickListener(null);
- groupRow.setFeedbackIcon(null);
+ mGroupRow.setSensitive(true, true);
+ mGroupRow.setOnFeedbackClickListener(null);
+ mGroupRow.setFeedbackIcon(null);
}
@Test
- public void testFeedback_header() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
+ public void testFeedback_header() {
NotificationContentView publicLayout = mock(NotificationContentView.class);
- group.setPublicLayout(publicLayout);
+ mGroupRow.setPublicLayout(publicLayout);
NotificationContentView privateLayout = mock(NotificationContentView.class);
- group.setPrivateLayout(privateLayout);
+ mGroupRow.setPrivateLayout(privateLayout);
NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
when(mockContainer.getNotificationChildCount()).thenReturn(1);
- group.setChildrenContainer(mockContainer);
+ mGroupRow.setChildrenContainer(mockContainer);
final boolean show = true;
final FeedbackIcon icon = new FeedbackIcon(
R.drawable.ic_feedback_alerted, R.string.notification_feedback_indicator_alerted);
- group.setFeedbackIcon(icon);
+ mGroupRow.setFeedbackIcon(icon);
verify(mockContainer, times(1)).setFeedbackIcon(icon);
verify(privateLayout, times(1)).setFeedbackIcon(icon);
@@ -372,49 +346,43 @@ public void testFeedback_header() throws Exception {
}
@Test
- public void testFeedbackOnClick() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
+ public void testFeedbackOnClick() {
ExpandableNotificationRow.CoordinateOnClickListener l = mock(
ExpandableNotificationRow.CoordinateOnClickListener.class);
View view = mock(View.class);
- group.setOnFeedbackClickListener(l);
+ mGroupRow.setOnFeedbackClickListener(l);
- group.getFeedbackOnClickListener().onClick(view);
+ mGroupRow.getFeedbackOnClickListener().onClick(view);
verify(l, times(1)).onClick(any(), anyInt(), anyInt(), any());
}
@Test
- public void testHeadsUpAnimatingAwayListener() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- Consumer<Boolean> headsUpListener = mock(Consumer.class);
- AboveShelfChangedListener aboveShelfChangedListener = mock(AboveShelfChangedListener.class);
- group.setHeadsUpAnimatingAwayListener(headsUpListener);
- group.setAboveShelfChangedListener(aboveShelfChangedListener);
-
- group.setHeadsUpAnimatingAway(true);
- verify(headsUpListener).accept(true);
- verify(aboveShelfChangedListener).onAboveShelfStateChanged(true);
-
- group.setHeadsUpAnimatingAway(false);
- verify(headsUpListener).accept(false);
- verify(aboveShelfChangedListener).onAboveShelfStateChanged(false);
+ public void testHeadsUpAnimatingAwayListener() {
+ mGroupRow.setHeadsUpAnimatingAway(true);
+ Assert.assertEquals(true, mHeadsUpAnimatingAway);
+ mGroupRow.setHeadsUpAnimatingAway(false);
+ Assert.assertEquals(false, mHeadsUpAnimatingAway);
}
@Test
- public void testGetNumUniqueChildren_defaultChannel() throws Exception {
- ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
+ public void testIsBlockingHelperShowing_isCorrectlyUpdated() {
+ mGroupRow.setBlockingHelperShowing(true);
+ assertTrue(mGroupRow.isBlockingHelperShowing());
- assertEquals(1, groupRow.getNumUniqueChannels());
+ mGroupRow.setBlockingHelperShowing(false);
+ assertFalse(mGroupRow.isBlockingHelperShowing());
}
@Test
- public void testGetNumUniqueChildren_multiChannel() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
+ public void testGetNumUniqueChildren_defaultChannel() {
+ assertEquals(1, mGroupRow.getNumUniqueChannels());
+ }
+ @Test
+ public void testGetNumUniqueChildren_multiChannel() {
List<ExpandableNotificationRow> childRows =
- group.getChildrenContainer().getAttachedChildren();
+ mGroupRow.getChildrenContainer().getAttachedChildren();
// Give each child a unique channel id/name.
int i = 0;
for (ExpandableNotificationRow childRow : childRows) {
@@ -426,29 +394,25 @@ public void testGetNumUniqueChildren_multiChannel() throws Exception {
i++;
}
- assertEquals(3, group.getNumUniqueChannels());
+ assertEquals(3, mGroupRow.getNumUniqueChannels());
}
@Test
public void testIconScrollXAfterTranslationAndReset() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
- group.setDismissUsingRowTranslationX(false);
- group.setTranslation(50);
- assertEquals(50, -group.getEntry().getIcons().getShelfIcon().getScrollX());
+ mGroupRow.setDismissUsingRowTranslationX(false);
+ mGroupRow.setTranslation(50);
+ assertEquals(50, -mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX());
- group.resetTranslation();
- assertEquals(0, group.getEntry().getIcons().getShelfIcon().getScrollX());
+ mGroupRow.resetTranslation();
+ assertEquals(0, mGroupRow.getEntry().getIcons().getShelfIcon().getScrollX());
}
@Test
- public void testIsExpanded_userExpanded() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
-
- group.setExpandable(true);
- Assert.assertFalse(group.isExpanded());
- group.setUserExpanded(true);
- Assert.assertTrue(group.isExpanded());
+ public void testIsExpanded_userExpanded() {
+ mGroupRow.setExpandable(true);
+ Assert.assertFalse(mGroupRow.isExpanded());
+ mGroupRow.setUserExpanded(true);
+ Assert.assertTrue(mGroupRow.isExpanded());
}
@Test
@@ -492,230 +456,22 @@ public void testCannotDismissOngoing() throws Exception {
}
@Test
- public void testAddChildNotification() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(0);
- ExpandableNotificationRow child = mNotificationTestHelper.createRow();
+ public void imageResolver_sameNotificationUser_usesContext() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(PKG,
+ USER_HANDLE.getUid(1234), USER_HANDLE);
- group.addChildNotification(child);
-
- Assert.assertEquals(child, group.getChildNotificationAt(0));
- Assert.assertEquals(group, child.getNotificationParent());
- Assert.assertTrue(child.isChildInGroup());
+ assertThat(row.getImageResolver().getContext()).isSameInstanceAs(mContext);
}
@Test
- public void testAddChildNotification_childSkipped() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(0);
- ExpandableNotificationRow child = mNotificationTestHelper.createRow();
- child.setKeepInParentForDismissAnimation(true);
-
- group.addChildNotification(child);
-
- Assert.assertTrue(group.getAttachedChildren().isEmpty());
- Assert.assertNotEquals(group, child.getNotificationParent());
- verify(mNotificationTestHelper.getMockLogger()).logSkipAttachingKeepInParentChild(
- /*child=*/ child.getEntry(),
- /*newParent=*/ group.getEntry()
- );
- }
+ public void imageResolver_differentNotificationUser_createsUserContext() throws Exception {
+ UserHandle user = new UserHandle(33);
+ Context userContext = new SysuiTestableContext(mContext);
+ mContext.prepareCreateContextAsUser(user, userContext);
- @Test
- public void testRemoveChildNotification() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(1);
- ExpandableNotificationRow child = group.getAttachedChildren().get(0);
- child.setKeepInParentForDismissAnimation(true);
-
- group.removeChildNotification(child);
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(PKG,
+ user.getUid(1234), user);
- Assert.assertNull(child.getParent());
- Assert.assertNull(child.getNotificationParent());
- Assert.assertFalse(child.keepInParentForDismissAnimation());
- verifyNoMoreInteractions(mNotificationTestHelper.getMockLogger());
- }
-
- @Test
- public void testRemoveChildrenWithKeepInParent_removesChildWithKeepInParent() throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(1);
- ExpandableNotificationRow child = group.getAttachedChildren().get(0);
- child.setKeepInParentForDismissAnimation(true);
-
- group.removeChildrenWithKeepInParent();
-
- Assert.assertNull(child.getParent());
- Assert.assertNull(child.getNotificationParent());
- Assert.assertFalse(child.keepInParentForDismissAnimation());
- verify(mNotificationTestHelper.getMockLogger()).logKeepInParentChildDetached(
- /*child=*/ child.getEntry(),
- /*oldParent=*/ group.getEntry()
- );
- }
-
- @Test
- public void testRemoveChildrenWithKeepInParent_skipsChildrenWithoutKeepInParent()
- throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup(1);
- ExpandableNotificationRow child = group.getAttachedChildren().get(0);
-
- group.removeChildrenWithKeepInParent();
-
- Assert.assertEquals(group, child.getNotificationParent());
- Assert.assertFalse(child.keepInParentForDismissAnimation());
- verify(mNotificationTestHelper.getMockLogger(), never()).logKeepInParentChildDetached(
- /*child=*/ any(),
- /*oldParent=*/ any()
- );
- }
-
- @Test
- public void applyRoundnessAndInv_should_be_immediately_applied_on_childrenContainer_legacy()
- throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- group.useRoundnessSourceTypes(false);
- Assert.assertEquals(0f, group.getBottomRoundness(), 0.001f);
- Assert.assertEquals(0f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
-
- group.requestBottomRoundness(1f, SourceType.from(""), false);
-
- Assert.assertEquals(1f, group.getBottomRoundness(), 0.001f);
- Assert.assertEquals(1f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
- }
-
- @Test
- public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_childrenContainer()
- throws Exception {
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- group.useRoundnessSourceTypes(true);
- Assert.assertEquals(0f, group.getBottomRoundness(), 0.001f);
- Assert.assertEquals(0f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
-
- group.requestBottomRoundness(1f, SourceType.from(""), false);
-
- Assert.assertEquals(1f, group.getBottomRoundness(), 0.001f);
- Assert.assertEquals(1f, group.getChildrenContainer().getBottomRoundness(), 0.001f);
- }
-
- @Test
- public void testSetContentAnimationRunning_Run() throws Exception {
- // Create views for the notification row.
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- NotificationContentView publicLayout = mock(NotificationContentView.class);
- row.setPublicLayout(publicLayout);
- NotificationContentView privateLayout = mock(NotificationContentView.class);
- row.setPrivateLayout(privateLayout);
-
- row.setAnimationRunning(true);
- verify(publicLayout, times(1)).setContentAnimationRunning(true);
- verify(privateLayout, times(1)).setContentAnimationRunning(true);
- }
-
- @Test
- public void testSetContentAnimationRunning_Stop() throws Exception {
- // Create views for the notification row.
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- NotificationContentView publicLayout = mock(NotificationContentView.class);
- row.setPublicLayout(publicLayout);
- NotificationContentView privateLayout = mock(NotificationContentView.class);
- row.setPrivateLayout(privateLayout);
-
- row.setAnimationRunning(false);
- verify(publicLayout, times(1)).setContentAnimationRunning(false);
- verify(privateLayout, times(1)).setContentAnimationRunning(false);
- }
-
- @Test
- public void testSetContentAnimationRunningInGroupChild_Run() throws Exception {
- // Creates parent views on groupRow.
- ExpandableNotificationRow groupRow = mNotificationTestHelper.createGroup();
- NotificationContentView publicParentLayout = mock(NotificationContentView.class);
- groupRow.setPublicLayout(publicParentLayout);
- NotificationContentView privateParentLayout = mock(NotificationContentView.class);
- groupRow.setPrivateLayout(privateParentLayout);
-
- // Create child views on row.
- ExpandableNotificationRow row = mNotificationTestHelper.createRow();
- NotificationContentView publicChildLayout = mock(NotificationContentView.class);
- row.setPublicLayout(publicChildLayout);
- NotificationContentView privateChildLayout = mock(NotificationContentView.class);
- row.setPrivateLayout(privateChildLayout);
- when(row.isGroupExpanded()).thenReturn(true);
- setMockChildrenContainer(groupRow, row);
-
- groupRow.setAnimationRunning(true);
- verify(publicParentLayout, times(1)).setContentAnimationRunning(true);
- verify(privateParentLayout, times(1)).setContentAnimationRunning(true);
- // The child layouts should be started too.
- verify(publicChildLayout, times(1)).setContentAnimationRunning(true);
- verify(privateChildLayout, times(1)).setContentAnimationRunning(true);
- }
-
-
- @Test
- public void testSetIconAnimationRunningGroup_Run() throws Exception {
- // Create views for a group row.
- ExpandableNotificationRow group = mNotificationTestHelper.createGroup();
- ExpandableNotificationRow child = mNotificationTestHelper.createRow();
- NotificationContentView publicParentLayout = mock(NotificationContentView.class);
- group.setPublicLayout(publicParentLayout);
- NotificationContentView privateParentLayout = mock(NotificationContentView.class);
- group.setPrivateLayout(privateParentLayout);
- when(group.isGroupExpanded()).thenReturn(true);
-
- // Add the child to the group.
- NotificationContentView publicChildLayout = mock(NotificationContentView.class);
- child.setPublicLayout(publicChildLayout);
- NotificationContentView privateChildLayout = mock(NotificationContentView.class);
- child.setPrivateLayout(privateChildLayout);
- when(child.isGroupExpanded()).thenReturn(true);
-
- NotificationChildrenContainer mockContainer =
- setMockChildrenContainer(group, child);
-
- // Mock the children view wrappers, and give them each an icon.
- NotificationViewWrapper mockViewWrapper = mock(NotificationViewWrapper.class);
- when(mockContainer.getNotificationViewWrapper()).thenReturn(mockViewWrapper);
- CachingIconView mockIcon = mock(CachingIconView.class);
- when(mockViewWrapper.getIcon()).thenReturn(mockIcon);
-
- NotificationViewWrapper mockLowPriorityViewWrapper = mock(NotificationViewWrapper.class);
- when(mockContainer.getLowPriorityViewWrapper()).thenReturn(mockLowPriorityViewWrapper);
- CachingIconView mockLowPriorityIcon = mock(CachingIconView.class);
- when(mockLowPriorityViewWrapper.getIcon()).thenReturn(mockLowPriorityIcon);
-
- // Give the icon image views drawables, so we can make sure they animate.
- // We use both AnimationDrawables and AnimatedVectorDrawables to ensure both work.
- AnimationDrawable drawable = mock(AnimationDrawable.class);
- AnimatedVectorDrawable vectorDrawable = mock(AnimatedVectorDrawable.class);
- setDrawableIconsInImageView(mockIcon, drawable, vectorDrawable);
-
- AnimationDrawable lowPriDrawable = mock(AnimationDrawable.class);
- AnimatedVectorDrawable lowPriVectorDrawable = mock(AnimatedVectorDrawable.class);
- setDrawableIconsInImageView(mockLowPriorityIcon, lowPriDrawable, lowPriVectorDrawable);
-
- group.setAnimationRunning(true);
- verify(drawable, times(1)).start();
- verify(vectorDrawable, times(1)).start();
- verify(lowPriDrawable, times(1)).start();
- verify(lowPriVectorDrawable, times(1)).start();
- }
-
- private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
- Drawable rightIconDrawable) {
- ImageView iconView = mock(ImageView.class);
- when(icon.findViewById(com.android.internal.R.id.icon)).thenReturn(iconView);
- when(iconView.getDrawable()).thenReturn(iconDrawable);
-
- ImageView rightIconView = mock(ImageView.class);
- when(icon.findViewById(com.android.internal.R.id.right_icon)).thenReturn(rightIconView);
- when(rightIconView.getDrawable()).thenReturn(rightIconDrawable);
- }
-
- private NotificationChildrenContainer setMockChildrenContainer(
- ExpandableNotificationRow parentRow, ExpandableNotificationRow childRow) {
- List<ExpandableNotificationRow> rowList = Arrays.asList(childRow);
- NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class);
- when(mockContainer.getNotificationChildCount()).thenReturn(1);
- when(mockContainer.getAttachedChildren()).thenReturn(rowList);
- parentRow.setChildrenContainer(mockContainer);
- return mockContainer;
+ assertThat(row.getImageResolver().getContext()).isSameInstanceAs(userContext);
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
index 0674ea855d7f..fd2914e02a76 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
@@ -14,6 +14,7 @@
package com.android.systemui;
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -28,12 +29,15 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
public class SysuiTestableContext extends TestableContext {
@GuardedBy("mRegisteredReceivers")
private final Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
+ private final Map<UserHandle, Context> mContextForUser = new HashMap<>();
public SysuiTestableContext(Context base) {
super(base);
@@ -146,4 +150,22 @@ public void unregisterReceiver(BroadcastReceiver receiver) {
}
super.unregisterReceiver(receiver);
}
+
+ /**
+ * Sets a Context object that will be returned as the result of {@link #createContextAsUser}
+ * for a specific {@code user}.
+ */
+ public void prepareCreateContextAsUser(UserHandle user, Context context) {
+ mContextForUser.put(user, context);
+ }
+
+ @Override
+ @NonNull
+ public Context createContextAsUser(UserHandle user, int flags) {
+ Context userContext = mContextForUser.get(user);
+ if (userContext != null) {
+ return userContext;
+ }
+ return super.createContextAsUser(user, flags);
+ }
}

View File

@ -1,274 +0,0 @@
From 56ef52af608d4c74da25da50023b63fb3680159f Mon Sep 17 00:00:00 2001
From: Beth Thibodeau <ethibodeau@google.com>
Date: Tue, 19 Mar 2024 16:49:51 -0500
Subject: [PATCH] Update media_controls_lock_screen setting behavior
When the setting is disabled, hide the media carousel everywhere when
the device is on lockscreen, not just in the keyguard layout
Bug: 314333719
Test: manual
Test: atest MediaHierarchyManagerTest
Flag: NONE
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a441f4acd62cce1059818ce8e9b7ab93b0079e50)
Merged-In: I4f618e4013db894291e6fca9d49bceb1cb7e4bd9
Change-Id: I4f618e4013db894291e6fca9d49bceb1cb7e4bd9
---
.../controls/ui/KeyguardMediaController.kt | 40 -------------------
.../controls/ui/MediaHierarchyManager.kt | 27 +++++++++----
.../systemui/media/controls/ui/MediaHost.kt | 4 +-
.../ui/KeyguardMediaControllerTest.kt | 28 -------------
4 files changed, 22 insertions(+), 77 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 30ee147e302a..2a2882cf7108 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -18,16 +18,10 @@ package com.android.systemui.media.controls.ui
import android.content.Context
import android.content.res.Configuration
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.os.UserHandle
-import android.provider.Settings
import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.StatusBarState
@@ -36,7 +30,6 @@ import com.android.systemui.statusbar.notification.stack.MediaContainerView
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.LargeScreenUtils
-import com.android.systemui.util.settings.SecureSettings
import javax.inject.Inject
import javax.inject.Named
@@ -52,8 +45,6 @@ constructor(
private val bypassController: KeyguardBypassController,
private val statusBarStateController: SysuiStatusBarStateController,
private val context: Context,
- private val secureSettings: SecureSettings,
- @Main private val handler: Handler,
configurationController: ConfigurationController,
) {
@@ -77,26 +68,6 @@ constructor(
}
)
- val settingsObserver: ContentObserver =
- object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- if (uri == lockScreenMediaPlayerUri) {
- allowMediaPlayerOnLockScreen =
- secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
- )
- refreshMediaPosition()
- }
- }
- }
- secureSettings.registerContentObserverForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- settingsObserver,
- UserHandle.USER_ALL
- )
-
// First let's set the desired state that we want for this host
mediaHost.expansion = MediaHostState.EXPANDED
mediaHost.showsOnlyActiveMedia = true
@@ -133,16 +104,6 @@ constructor(
private set
private var splitShadeContainer: ViewGroup? = null
- /** Track the media player setting status on lock screen. */
- private var allowMediaPlayerOnLockScreen: Boolean =
- secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
- )
- private val lockScreenMediaPlayerUri =
- secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
-
/**
* Attaches media container in single pane mode, situated at the top of the notifications list
*/
@@ -202,7 +163,6 @@ constructor(
mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
- allowMediaPlayerOnLockScreen &&
shouldBeVisibleForSplitShade()
if (visible) {
showMediaPlayer()
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 54237ce7cf25..f0ff1292311d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -104,7 +104,7 @@ constructor(
) {
/** Track the media player setting status on lock screen. */
- private var allowMediaPlayerOnLockScreen: Boolean = true
+ private var allowMediaPlayerOnLockScreen: Boolean = getMediaLockScreenSetting()
private val lockScreenMediaPlayerUri =
secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
@@ -462,6 +462,7 @@ constructor(
}
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
isVisibleToUser()
+ mediaCarouselController.updateHostVisibility()
}
override fun onDozeAmountChanged(linear: Float, eased: Float) {
@@ -538,7 +539,6 @@ constructor(
mediaCarouselController.updateHostVisibility = {
mediaHosts.forEach { it?.updateViewVisibility() }
}
-
panelEventsEvents.addShadeStateEventsListener(
object : ShadeStateEventsListener {
override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
@@ -552,12 +552,8 @@ constructor(
object : ContentObserver(handler) {
override fun onChange(selfChange: Boolean, uri: Uri?) {
if (uri == lockScreenMediaPlayerUri) {
- allowMediaPlayerOnLockScreen =
- secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
- )
+ allowMediaPlayerOnLockScreen = getMediaLockScreenSetting()
+ mediaCarouselController.updateHostVisibility()
}
}
}
@@ -568,6 +564,14 @@ constructor(
)
}
+ private fun getMediaLockScreenSetting(): Boolean {
+ return secureSettings.getBoolForUser(
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
+ )
+ }
+
private fun updateConfiguration() {
distanceForFullShadeTransition =
context.resources.getDimensionPixelSize(
@@ -607,6 +611,13 @@ constructor(
mediaCarouselController.closeGuts()
}
+ /** Return true if the carousel should be hidden because lockscreen is currently visible */
+ fun isLockedAndHidden(): Boolean {
+ return !allowMediaPlayerOnLockScreen &&
+ (statusbarState == StatusBarState.SHADE_LOCKED ||
+ statusbarState == StatusBarState.KEYGUARD)
+ }
+
private fun createUniqueObjectHost(): UniqueObjectHostView {
val viewHost = UniqueObjectHostView(context)
viewHost.addOnAttachStateChangeListener(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
index be570b4a1119..26580e54cd62 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
@@ -199,7 +199,9 @@ constructor(
*/
fun updateViewVisibility() {
state.visible =
- if (showsOnlyActiveMedia) {
+ if (mediaHierarchyManager.isLockedAndHidden()) {
+ false
+ } else if (showsOnlyActiveMedia) {
mediaDataManager.hasActiveMediaOrRecommendation()
} else {
mediaDataManager.hasAnyMediaOrRecommendation()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index b40ebc9bb156..41b3fe65599f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media.controls.ui
-import android.provider.Settings
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -32,8 +31,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.FakeSettings
-import com.android.systemui.utils.os.FakeHandler
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
import org.junit.Before
@@ -60,10 +57,7 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
private val hostView = UniqueObjectHostView(context)
- private val settings = FakeSettings()
private lateinit var keyguardMediaController: KeyguardMediaController
- private lateinit var testableLooper: TestableLooper
- private lateinit var fakeHandler: FakeHandler
private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@Before
@@ -79,16 +73,12 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
whenever(mediaHost.hostView).thenReturn(hostView)
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
- testableLooper = TestableLooper.get(this)
- fakeHandler = FakeHandler(testableLooper.looper)
keyguardMediaController =
KeyguardMediaController(
mediaHost,
bypassController,
statusBarStateController,
context,
- settings,
- fakeHandler,
configurationController,
)
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
@@ -117,24 +107,6 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
assertThat(mediaContainerView.visibility).isEqualTo(visibility)
}
- @Test
- fun testHiddenOnKeyguard_whenMediaOnLockScreenDisabled() {
- settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0)
-
- keyguardMediaController.refreshMediaPosition()
-
- assertThat(mediaContainerView.visibility).isEqualTo(GONE)
- }
-
- @Test
- fun testAvailableOnKeyguard_whenMediaOnLockScreenEnabled() {
- settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
-
- keyguardMediaController.refreshMediaPosition()
-
- assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
- }
-
@Test
fun testActivatesSplitShadeContainerInSplitShadeMode() {
val splitShadeContainer = FrameLayout(context)

View File

@ -1,64 +0,0 @@
From 9a005ebebfa638ed42415301fec30b16bef30299 Mon Sep 17 00:00:00 2001
From: Devin Moore <devinmoore@google.com>
Date: Mon, 22 Jan 2024 17:52:16 +0000
Subject: [PATCH] Use the values of the ptrs that we check
Test: fmq_fuzzer
Bug: 321326147
Bug: 321341508
Bug: 321383085
(cherry picked from https://android-review.googlesource.com/q/commit:38963310ad5789b625ca0bca9f9c2c8e24666651)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:050952bf5f9bd035e469ce005300115d563e524a)
Merged-In: I56fe4fe72180e39ecef066353969c1ae9fbcd44e
Change-Id: I56fe4fe72180e39ecef066353969c1ae9fbcd44e
---
include/fmq/MessageQueueBase.h | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/include/fmq/MessageQueueBase.h b/include/fmq/MessageQueueBase.h
index f4bf7e2..0bf0bb2 100644
--- a/include/fmq/MessageQueueBase.h
+++ b/include/fmq/MessageQueueBase.h
@@ -1034,8 +1034,16 @@ bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t
}
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
-size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
- return mDesc->getSize() - availableToReadBytes();
+inline size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
+ size_t queueSizeBytes = mDesc->getSize();
+ size_t availableBytes = availableToReadBytes();
+ if (queueSizeBytes < availableBytes) {
+ hardware::details::logError(
+ "The write or read pointer has become corrupted. Reading from the queue is no "
+ "longer possible.");
+ return 0;
+ }
+ return queueSizeBytes - availableBytes;
}
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
@@ -1117,13 +1125,21 @@ MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
}
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
-size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
+inline size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
/*
* This method is invoked by implementations of both read() and write() and
* hence requires a memory_order_acquired load for both mReadPtr and
* mWritePtr.
*/
- return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
+ uint64_t writePtr = mWritePtr->load(std::memory_order_acquire);
+ uint64_t readPtr = mReadPtr->load(std::memory_order_acquire);
+ if (writePtr < readPtr) {
+ hardware::details::logError(
+ "The write or read pointer has become corrupted. Reading from the queue is no "
+ "longer possible.");
+ return 0;
+ }
+ return writePtr - readPtr;
}
template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>

View File

@ -1,87 +0,0 @@
From 7c36c8764f78a135a4d273e8ff7200beef767e18 Mon Sep 17 00:00:00 2001
From: Vova Sharaienko <sharaienko@google.com>
Date: Wed, 27 Mar 2024 23:21:03 +0000
Subject: [PATCH] [libstatssocket] Added validation for adding new data into
StatsEvent
Bug: 330054251
Test: atest StatsEventTest#TestHeapBufferOverflowError
Ignore-AOSP-First: security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4f6c56889356a5a422b59c71e9142875d00e43bf)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e440696c4fd6d44d21451467294b3e31c6867e08)
Merged-In: I27c69d9875b494f98a2a961cdd4fe139cd809387
Change-Id: I27c69d9875b494f98a2a961cdd4fe139cd809387
---
lib/libstatssocket/stats_event.c | 3 ++
lib/libstatssocket/tests/stats_event_test.cpp | 44 +++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/lib/libstatssocket/stats_event.c b/lib/libstatssocket/stats_event.c
index 9bb4c52c4..828ff3e4f 100644
--- a/lib/libstatssocket/stats_event.c
+++ b/lib/libstatssocket/stats_event.c
@@ -330,6 +330,9 @@ void AStatsEvent_writeStringArray(AStatsEvent* event, const char* const* element
// Side-effect: modifies event->errors if field has too many annotations
static void increment_annotation_count(AStatsEvent* event) {
+ if (event->lastFieldPos >= event->bufSize) {
+ return;
+ }
uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
uint32_t newAnnotationCount = oldAnnotationCount + 1;
diff --git a/lib/libstatssocket/tests/stats_event_test.cpp b/lib/libstatssocket/tests/stats_event_test.cpp
index 93a99f1bf..dea81c256 100644
--- a/lib/libstatssocket/tests/stats_event_test.cpp
+++ b/lib/libstatssocket/tests/stats_event_test.cpp
@@ -536,6 +536,50 @@ TEST(StatsEventTest, TestPushOverflowError) {
AStatsEvent_release(event);
}
+TEST(StatsEventTest, TestHeapBufferOverflowError) {
+ const std::string testString(4039, 'A');
+ const std::string testString2(47135, 'B');
+
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
+
+ AStatsEvent_writeString(event, testString.c_str());
+ size_t bufferSize = 0;
+ AStatsEvent_getBuffer(event, &bufferSize);
+ EXPECT_EQ(bufferSize, 4060);
+ uint32_t errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors, 0);
+
+ // expand the buffer and fill with data up to the very last byte
+ AStatsEvent_writeString(event, testString2.c_str());
+ bufferSize = 0;
+ AStatsEvent_getBuffer(event, &bufferSize);
+ EXPECT_EQ(bufferSize, 50 * 1024);
+
+ errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors, 0);
+
+ // this write is no-op due to buffer reached its max capacity
+ // should set the overflow flag
+ AStatsEvent_writeString(event, testString2.c_str());
+ bufferSize = 0;
+ AStatsEvent_getBuffer(event, &bufferSize);
+ EXPECT_EQ(bufferSize, 50 * 1024);
+
+ errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
+
+ // here should be crash
+ AStatsEvent_addBoolAnnotation(event, 1, false);
+
+ AStatsEvent_write(event);
+
+ errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
+
+ AStatsEvent_release(event);
+}
+
TEST(StatsEventTest, TestPullOverflowError) {
const uint32_t atomId = 10100;
const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);

@ -1 +1 @@
Subproject commit 0c7d85395415ff295e974bbb88c6d153198eb8fa
Subproject commit 9e479b9b8623a38621a3195b10734322b8108bf5

View File

@ -93,7 +93,7 @@ applyPatch "$DOS_PATCHES_COMMON/android_build/0001-verity-openssl3.patch"; #Fix
sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aapt2.mk; #Enable auto-add-overlay for packages, this allows the vendor overlay to easily work across all branches.
awk -i inplace '!/updatable_apex.mk/' target/product/mainline_system.mk; #Disable APEX
sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_defaults.mk; #Set the minimum supported target SDK to Pie (GrapheneOS)
sed -i 's/2024-02-05/2024-05-05/' core/version_defaults.mk; #Bump Security String #x_asb_2024-04
sed -i 's/2024-02-05/2024-06-05/' core/version_defaults.mk; #Bump Security String #R_asb_2024-06
fi;
if enterAndClear "build/soong"; then
@ -145,6 +145,17 @@ applyPatch "$DOS_PATCHES/android_frameworks_base/389132.patch"; #R_asb_2024-04 i
applyPatch "$DOS_PATCHES/android_frameworks_base/389133.patch"; #R_asb_2024-04 Fix security vulnerability that creates user with no restrictions when accountOptions are too long.
applyPatch "$DOS_PATCHES/android_frameworks_base/392206.patch"; #R_asb_2024-05 Don't try to show the current toast again while it's showing.
applyPatch "$DOS_PATCHES/android_frameworks_base/392207.patch"; #R_asb_2024-05 Prioritize system toasts
applyPatch "$DOS_PATCHES/android_frameworks_base/394553.patch"; #R_asb_2024-06 ActivityManager#killBackgroundProcesses can kill caller's own app only
applyPatch "$DOS_PATCHES/android_frameworks_base/394554.patch"; #R_asb_2024-06 Fix ActivityManager#killBackgroundProcesses permissions
applyPatch "$DOS_PATCHES/android_frameworks_base/394555.patch"; #R_asb_2024-06 Verify URI permission for channel sound update from NotificationListenerService
applyPatch "$DOS_PATCHES/android_frameworks_base/394556.patch"; #R_asb_2024-06 Check for NLS bind permission when rebinding services
applyPatch "$DOS_PATCHES/android_frameworks_base/394557.patch"; #R_asb_2024-06 Hide window immediately if itself doesn't run hide animation
applyPatch "$DOS_PATCHES/android_frameworks_base/394558.patch"; #R_asb_2024-06 Fix error handling for non-dynamic permissions
applyPatch "$DOS_PATCHES/android_frameworks_base/394559.patch"; #R_asb_2024-06 Add more checkKeyIntent checks to AccountManagerService.
applyPatch "$DOS_PATCHES/android_frameworks_base/394560.patch"; #R_asb_2024-06 Add in check for intent filter when setting/updating service
applyPatch "$DOS_PATCHES/android_frameworks_base/394561.patch"; #R_asb_2024-06 Check hidden API exemptions
applyPatch "$DOS_PATCHES/android_frameworks_base/394562.patch"; #R_asb_2024-06 AccessibilityManagerService: remove uninstalled services from enabled list after service update.
applyPatch "$DOS_PATCHES/android_frameworks_base/394563.patch"; #R_asb_2024-06 Check permissions for CDM shell commands
git revert --no-edit 438d9feacfcad73d3ee918541574132928a93644; #Reverts "Allow signature spoofing for microG Companion/Services" in favor of below patch
applyPatch "$DOS_PATCHES/android_frameworks_base/0007-Always_Restict_Serial.patch"; #Always restrict access to Build.SERIAL (GrapheneOS)
applyPatch "$DOS_PATCHES/android_frameworks_base/0008-Browser_No_Location.patch"; #Don't grant location permission to system browsers (GrapheneOS)

View File

@ -66,8 +66,9 @@ patchWorkspaceReal() {
verifyAllPlatformTags;
gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview";
#source build/envsetup.sh;
source build/envsetup.sh;
#repopick -ift twelve-bt-sbc-hd-dualchannel;
repopick -it S_asb_2024-06 -e 394523,394543;
sh "$DOS_SCRIPTS/Patch.sh";
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";

View File

@ -95,6 +95,7 @@ applyPatch "$DOS_PATCHES_COMMON/android_build/0001-verity-openssl3.patch"; #Fix
sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aapt2.mk; #Enable auto-add-overlay for packages, this allows the vendor overlay to easily work across all branches.
awk -i inplace '!/updatable_apex.mk/' target/product/generic_system.mk; #Disable APEX
sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_defaults.mk; #Set the minimum supported target SDK to Pie (GrapheneOS)
sed -i 's/2024-05-05/2024-06-05/' core/version_defaults.mk; #Bump Security String #S_asb_2024-06
fi;
if enterAndClear "build/soong"; then
@ -394,6 +395,10 @@ if enterAndClear "system/extras"; then
applyPatch "$DOS_PATCHES/android_system_extras/0001-ext4_pad_filenames.patch"; #FBE: pad filenames more (GrapheneOS)
fi;
if enterAndClear "system/libfmq"; then
git fetch https://github.com/LineageOS/android_system_libfmq refs/changes/43/394543/1 && git cherry-pick FETCH_HEAD; #S_asb_2024-06
fi;
if enterAndClear "system/netd"; then
applyPatch "$DOS_PATCHES/android_system_netd/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS)
fi;

View File

@ -162,7 +162,8 @@ patchWorkspaceReal() {
verifyAllPlatformTags;
gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview";
#source build/envsetup.sh;
source build/envsetup.sh;
repopick -it T_asb_2024-06 -e 394238,394253;
sh "$DOS_SCRIPTS/Patch.sh";
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";

View File

@ -94,7 +94,6 @@ applyPatch "$DOS_PATCHES/android_build/0003-Exec_Based_Spawning.patch"; #Add exe
applyPatch "$DOS_PATCHES/android_build/0004-Selective_APEX.patch"; #Only enable APEX on 6th/7th gen Pixel devices (GrapheneOS)
sed -i '75i$(my_res_package): PRIVATE_AAPT_FLAGS += --auto-add-overlay' core/aapt2.mk; #Enable auto-add-overlay for packages, this allows the vendor overlay to easily work across all branches.
sed -i 's/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 23/PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION := 28/' core/version_util.mk; #Set the minimum supported target SDK to Pie (GrapheneOS)
sed -i 's/2024-05-05/2024-06-05/' core/version_defaults.mk; #Bump Security String #x_asb_2024-06
fi;
if enterAndClear "build/soong"; then
@ -118,12 +117,7 @@ sed -i 's/34359738368/2147483648/' Android.bp; #revert 48-bit address space requ
sed -i -e '76,78d;' Android.bp; #fix compile under A13
fi;
if enterAndClear "frameworks/av"; then
git am $DOS_PATCHES/ASB-2023-10/av-*.patch;
fi;
if enterAndClear "frameworks/base"; then
git am $DOS_PATCHES/ASB-2024-06/fwb-*.patch;
git revert --no-edit d36faad3267522c6d3ff91ba9dcca8f6274bccd1; #Reverts "JobScheduler: Respect allow-in-power-save perm" in favor of below patch
git revert --no-edit 90d6826548189ca850d91692e71fcc1be426f453; #Reverts "Remove sensitive info from SUPL requests" in favor of below patch
git revert --no-edit 6d2955f0bd55e9938d5d49415182c27b50900b95; #Reverts "Allow signature spoofing for microG Companion/Services" in favor of below patch
@ -406,7 +400,7 @@ applyPatch "$DOS_PATCHES/android_system_extras/0001-ext4_pad_filenames.patch"; #
fi;
if enterAndClear "system/libfmq"; then
git am $DOS_PATCHES/ASB-2024-06/libfmq-*.patch;
git fetch https://github.com/LineageOS/android_system_libfmq refs/changes/53/394253/1 && git cherry-pick FETCH_HEAD; #T_asb_2024-06
fi;
if enterAndClear "system/sepolicy"; then