mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
Reconcile picks
Signed-off-by: Tavi <tavi@divested.dev>
This commit is contained in:
parent
0b746cecf4
commit
ba9e22dc77
47
Patches/LineageOS-18.1/android_frameworks_base/394553.patch
Normal file
47
Patches/LineageOS-18.1/android_frameworks_base/394553.patch
Normal 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) {
|
46
Patches/LineageOS-18.1/android_frameworks_base/394554.patch
Normal file
46
Patches/LineageOS-18.1/android_frameworks_base/394554.patch
Normal 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) {
|
@ -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>
|
From: Valentin Iftime <valiiftime@google.com>
|
||||||
Date: Thu, 1 Feb 2024 13:58:49 +0100
|
Date: Thu, 1 Feb 2024 13:58:49 +0100
|
||||||
Subject: [PATCH] Verify URI permission for channel sound update from
|
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
|
Test: atest com.android.server.notification.NotificationManagerServiceTest#testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission
|
||||||
Bug: 317357401
|
Bug: 317357401
|
||||||
(cherry picked from commit 9b7bbbf5ad542ecf9ecbf8cd819b468791b443c0)
|
(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
|
Merged-In: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
|
||||||
Change-Id: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
|
Change-Id: Ic7d2e96e43565e98d2aa29b8f2ba35c142387ba9
|
||||||
---
|
---
|
||||||
.../NotificationManagerService.java | 22 +++++++
|
.../NotificationManagerService.java | 22 ++++++
|
||||||
.../NotificationManagerServiceTest.java | 63 +++++++++++++++++++
|
.../NotificationManagerServiceTest.java | 67 +++++++++++++++++++
|
||||||
2 files changed, 85 insertions(+)
|
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
|
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
|
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
|
||||||
+++ b/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);
|
Objects.requireNonNull(user);
|
||||||
|
|
||||||
verifyPrivilegedListener(token, user, false);
|
verifyPrivilegedListener(token, user, false);
|
||||||
@ -33,7 +33,7 @@ index ecd446519c09..4d1abc61aa73 100755
|
|||||||
updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
|
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 {
|
private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
|
||||||
int uid = INVALID_UID;
|
int uid = 0;
|
||||||
final long identity = Binder.clearCallingIdentity();
|
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
|
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
|
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
|
||||||
+++ b/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));
|
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,8 +70,10 @@ index 4f0a7ca0ad51..755bc1d35cf3 100755
|
|||||||
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
|
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()
|
||||||
+ throws Exception {
|
+ throws Exception {
|
||||||
+ mService.setPreferencesHelper(mPreferencesHelper);
|
+ mService.setPreferencesHelper(mPreferencesHelper);
|
||||||
|
+ List<String> associations = new ArrayList<>();
|
||||||
|
+ associations.add("a");
|
||||||
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
|
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
|
||||||
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
|
+ .thenReturn(associations);
|
||||||
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
|
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
|
||||||
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
|
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
|
||||||
+ .thenReturn(mTestNotificationChannel);
|
+ .thenReturn(mTestNotificationChannel);
|
||||||
@ -102,8 +104,10 @@ index 4f0a7ca0ad51..755bc1d35cf3 100755
|
|||||||
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
|
+ public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()
|
||||||
+ throws Exception {
|
+ throws Exception {
|
||||||
+ mService.setPreferencesHelper(mPreferencesHelper);
|
+ mService.setPreferencesHelper(mPreferencesHelper);
|
||||||
|
+ List<String> associations = new ArrayList<>();
|
||||||
|
+ associations.add("a");
|
||||||
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
|
+ when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
|
||||||
+ .thenReturn(singletonList(mock(AssociationInfo.class)));
|
+ .thenReturn(associations);
|
||||||
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
|
+ when(mPreferencesHelper.getNotificationChannel(eq(PKG), anyInt(),
|
||||||
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
|
+ eq(mTestNotificationChannel.getId()), anyBoolean()))
|
||||||
+ .thenReturn(mTestNotificationChannel);
|
+ .thenReturn(mTestNotificationChannel);
|
270
Patches/LineageOS-18.1/android_frameworks_base/394556.patch
Normal file
270
Patches/LineageOS-18.1/android_frameworks_base/394556.patch
Normal 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}) {
|
@ -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>
|
From: Riddle Hsu <riddlehsu@google.com>
|
||||||
Date: Tue, 6 Feb 2024 17:19:37 +0800
|
Date: Tue, 6 Feb 2024 17:19:37 +0800
|
||||||
Subject: [PATCH] Hide window immediately if itself doesn't run hide animation
|
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(-)
|
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
|
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
|
--- a/services/core/java/com/android/server/wm/WindowState.java
|
||||||
+++ b/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;
|
return false;
|
||||||
}
|
}
|
||||||
if (doAnimation) {
|
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
|
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
|
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
|
||||||
+++ b/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());
|
assertTrue(window.isOnScreen());
|
||||||
window.hide(false /* doAnimation */, false /* requestAnim */);
|
window.hideLw(false /* doAnimation */);
|
||||||
assertFalse(window.isOnScreen());
|
assertFalse(window.isOnScreen());
|
||||||
+
|
+
|
||||||
+ // Verifies that a window without animation can be hidden even if its parent is animating.
|
+ // Verifies that a window without animation can be hidden even if its parent is animating.
|
@ -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>
|
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
|
Subject: [PATCH] Fix error handling for non-dynamic permissions
|
||||||
|
|
||||||
We only allow removing dynamic permissions. When removePermission() is
|
We only allow removing dynamic permissions. When removePermission() is
|
||||||
@ -10,22 +10,22 @@ should also return early to avoid the removePermission() call.
|
|||||||
Test: manual
|
Test: manual
|
||||||
Bug: 321555066
|
Bug: 321555066
|
||||||
Fixes: 321711213
|
Fixes: 321711213
|
||||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:528a87e90ff9354581d54fd37fbe9f95cccbcdb1)
|
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2b5d63b64b2b8208ccc4f62eac3d8962f981dbf8)
|
||||||
Merged-In: Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5
|
Merged-In: I7336f2fc78804f26e4b2a329870ecdea776595d8
|
||||||
Change-Id: Ie2f43663bc71a06ffadb868d2d0eea5ee78f76e5
|
Change-Id: I7336f2fc78804f26e4b2a329870ecdea776595d8
|
||||||
---
|
---
|
||||||
.../server/pm/permission/PermissionManagerServiceImpl.java | 1 +
|
.../android/server/pm/permission/PermissionManagerService.java | 1 +
|
||||||
1 file changed, 1 insertion(+)
|
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
|
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 5dc7e23c01e2..1ec3403a9d46 100644
|
index f83c3d5145cc7..eb27a13523baf 100644
|
||||||
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
|
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
|
||||||
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
|
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
|
||||||
@@ -681,6 +681,7 @@ public void removePermission(String permName) {
|
@@ -645,6 +645,7 @@ public void removePermission(String permName) {
|
||||||
// TODO: switch this back to SecurityException
|
// TODO: switch this back to SecurityException
|
||||||
Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
|
Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
|
||||||
+ permName);
|
+ permName);
|
||||||
+ return;
|
+ return;
|
||||||
}
|
}
|
||||||
mRegistry.removePermission(permName);
|
mSettings.removePermissionLocked(permName);
|
||||||
}
|
mPackageManagerInt.writeSettings(false);
|
@ -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>
|
From: Dmitry Dementyev <dementyev@google.com>
|
||||||
Date: Tue, 26 Mar 2024 10:31:44 -0700
|
Date: Tue, 26 Mar 2024 10:31:44 -0700
|
||||||
Subject: [PATCH] Add more checkKeyIntent checks to AccountManagerService.
|
Subject: [PATCH] Add more checkKeyIntent checks to AccountManagerService.
|
||||||
@ -14,10 +14,10 @@ Change-Id: I9e45d758a2320328da5664b6341eafe6f285f297
|
|||||||
1 file changed, 10 insertions(+)
|
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
|
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
|
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
|
||||||
+++ b/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.
|
// Strip auth token from result.
|
||||||
result.remove(AccountManager.KEY_AUTHTOKEN);
|
result.remove(AccountManager.KEY_AUTHTOKEN);
|
||||||
@ -29,7 +29,7 @@ index 1c3564bfdba2..bc13f106ce6e 100644
|
|||||||
|
|
||||||
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
if (Log.isLoggable(TAG, Log.VERBOSE)) {
|
||||||
Log.v(TAG,
|
Log.v(TAG,
|
||||||
@@ -5146,6 +5151,11 @@ public void onResult(Bundle result) {
|
@@ -5052,6 +5057,11 @@ public void onResult(Bundle result) {
|
||||||
} else {
|
} else {
|
||||||
if (mStripAuthTokenFromResult) {
|
if (mStripAuthTokenFromResult) {
|
||||||
result.remove(AccountManager.KEY_AUTHTOKEN);
|
result.remove(AccountManager.KEY_AUTHTOKEN);
|
@ -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>
|
From: Haoran Zhang <haoranzhang@google.com>
|
||||||
Date: Wed, 13 Mar 2024 17:08:00 +0000
|
Date: Wed, 13 Mar 2024 17:08:00 +0000
|
||||||
Subject: [PATCH] [DO NOT MERGE][Autofill Framework] Add in check for intent
|
Subject: [PATCH] Add in check for intent filter when setting/updating service
|
||||||
filter when setting/updating service
|
|
||||||
|
|
||||||
For test, I registered two tests around on ABTD. CtsAutoFillServiceTestCases module is passing except three known failures:
|
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/L33300030002610600
|
||||||
- https://android-build.corp.google.com/builds/abtd/run/L58100030002616607
|
- https://android-build.corp.google.com/builds/abtd/run/L58100030002616607
|
||||||
|
|
||||||
|
|
||||||
Bug: b/324874908
|
Bug: b/324874908
|
||||||
Test: atest CtsAutoFillServiceTestCases
|
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: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
|
Merged-In: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
|
||||||
Change-Id: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
|
Change-Id: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
|
||||||
---
|
---
|
||||||
@ -22,12 +20,12 @@ Change-Id: I51c2e3788ac29ff4d6b86aa2a735ff2ea1463a77
|
|||||||
1 file changed, 27 insertions(+)
|
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
|
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
|
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
|
||||||
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
|
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
|
||||||
@@ -32,8 +32,10 @@
|
@@ -32,8 +32,10 @@
|
||||||
import android.annotation.Nullable;
|
import android.app.ActivityTaskManager;
|
||||||
import android.app.ActivityManagerInternal;
|
import android.app.IActivityTaskManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
+import android.content.Intent;
|
+import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
@ -36,7 +34,7 @@ index 20b2a74f5be5..2cda39d4b065 100644
|
|||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.metrics.LogMaker;
|
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
|
@Override // from PerUserSystemService
|
||||||
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
|
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
|
||||||
throws NameNotFoundException {
|
throws NameNotFoundException {
|
@ -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>
|
From: Hans Boehm <hboehm@google.com>
|
||||||
Date: Tue, 2 Jan 2024 16:53:13 -0800
|
Date: Tue, 2 Jan 2024 16:53:13 -0800
|
||||||
Subject: [PATCH] Check hidden API exemptions
|
Subject: [PATCH] Check hidden API exemptions
|
||||||
@ -18,7 +18,7 @@ Change-Id: I83cd60e46407a4a082f9f3c80e937dbd522dbac4
|
|||||||
1 file changed, 10 insertions(+)
|
1 file changed, 10 insertions(+)
|
||||||
|
|
||||||
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
|
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
|
--- a/core/java/android/os/ZygoteProcess.java
|
||||||
+++ b/core/java/android/os/ZygoteProcess.java
|
+++ b/core/java/android/os/ZygoteProcess.java
|
||||||
@@ -431,6 +431,8 @@ private Process.ProcessStartResult zygoteSendArgsAndGetResult(
|
@@ -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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ for (/* NonNull */ String s : mApiDenylistExemptions) {
|
+ for (/* NonNull */ String s : mApiBlacklistExemptions) {
|
||||||
+ // indexOf() is intrinsified and faster than contains().
|
+ // indexOf() is intrinsified and faster than contains().
|
||||||
+ if (s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0 || s.indexOf('\u0000') >= 0) {
|
+ 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");
|
+ Slog.e(LOG_TAG, "Failed to set API denylist exemptions: Bad character");
|
||||||
+ mApiDenylistExemptions = Collections.emptyList();
|
+ mApiBlacklistExemptions = Collections.emptyList();
|
||||||
+ return false;
|
+ return false;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
try {
|
try {
|
||||||
state.mZygoteOutputWriter.write(Integer.toString(mApiDenylistExemptions.size() + 1));
|
state.mZygoteOutputWriter.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
|
||||||
state.mZygoteOutputWriter.newLine();
|
state.mZygoteOutputWriter.newLine();
|
@ -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>
|
From: Ameer Armaly <aarmaly@google.com>
|
||||||
Date: Fri, 8 Mar 2024 19:41:06 +0000
|
Date: Fri, 8 Mar 2024 19:41:06 +0000
|
||||||
Subject: [PATCH] [RESTRICT AUTOMERGE] AccessibilityManagerService: remove
|
Subject: [PATCH] AccessibilityManagerService: remove uninstalled services from
|
||||||
uninstalled services from enabled list after service update.
|
enabled list after service update.
|
||||||
|
|
||||||
Bug: 326485767
|
Bug: 326485767
|
||||||
Test: atest AccessibilityEndToEndTest#testUpdateServiceWithoutIntent_disablesService
|
Test: atest AccessibilityEndToEndTest#testUpdateServiceWithoutIntent_disablesService
|
||||||
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:766911c3312573196b33efd1c3c29ccece806846)
|
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5405514a23edcba0cf30e6ec78189e3f4e7d95cf)
|
||||||
Merged-In: I958d58953b300c8093335a22e207baac471ae9f9
|
Merged-In: I5e59296fcad68e62b34c74ee5fd80b6ad6b46fa1
|
||||||
Change-Id: I958d58953b300c8093335a22e207baac471ae9f9
|
Change-Id: I5e59296fcad68e62b34c74ee5fd80b6ad6b46fa1
|
||||||
---
|
---
|
||||||
.../AccessibilityManagerService.java | 22 +++++++++++++++++++
|
.../AccessibilityManagerService.java | 22 +++++++++++++++++++
|
||||||
1 file changed, 22 insertions(+)
|
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
|
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
|
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
|
||||||
+++ b/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)
|
boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class)
|
||||||
.isUserUnlockingOrUnlocked(userState.mUserId);
|
.isUserUnlockingOrUnlocked(userState.mUserId);
|
||||||
|
|
||||||
@ -31,10 +31,10 @@ index 3818a884c94a..8271aed181c9 100644
|
|||||||
|
|
||||||
AccessibilityServiceConnection service = componentNameToServiceMap.get(componentName);
|
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);
|
audioManager.setAccessibilityServiceUids(mTempIntArray);
|
||||||
}
|
}
|
||||||
mActivityTaskManagerService.setAccessibilityServiceUids(mTempIntArray);
|
|
||||||
+ // If any services have been removed, remove them from the enabled list and the touch
|
+ // If any services have been removed, remove them from the enabled list and the touch
|
||||||
+ // exploration granted list.
|
+ // exploration granted list.
|
||||||
+ boolean anyServiceRemoved =
|
+ boolean anyServiceRemoved =
|
@ -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>
|
From: Guojing Yuan <guojing@google.com>
|
||||||
Date: Thu, 14 Dec 2023 19:30:04 +0000
|
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
|
Override handleShellCommand instead of onShellCommand because
|
||||||
Binder.onShellCommand checks the necessary permissions of the caller.
|
Binder.onShellCommand checks the necessary permissions of the caller.
|
||||||
@ -10,52 +10,52 @@ Bug: 313428840
|
|||||||
|
|
||||||
Test: manually tested CDM shell commands
|
Test: manually tested CDM shell commands
|
||||||
(cherry picked from commit 1761a0fee9c2cd9787bbb7fbdbe30b4c2b03396e)
|
(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
|
Merged-In: I5539b3594feb5544c458c0fd1061b51a0a808900
|
||||||
Change-Id: I5539b3594feb5544c458c0fd1061b51a0a808900
|
Change-Id: I5539b3594feb5544c458c0fd1061b51a0a808900
|
||||||
---
|
---
|
||||||
.../CompanionDeviceManagerService.java | 20 ++++++++-----------
|
.../companion/CompanionDeviceManagerService.java | 14 ++++++++------
|
||||||
1 file changed, 8 insertions(+), 12 deletions(-)
|
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
|
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
|
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
|
||||||
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
|
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
|
||||||
@@ -75,12 +75,11 @@
|
@@ -28,6 +28,7 @@
|
||||||
import android.os.Handler;
|
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||||
import android.os.Message;
|
|
||||||
|
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.Parcel;
|
||||||
+import android.os.ParcelFileDescriptor;
|
+import android.os.ParcelFileDescriptor;
|
||||||
import android.os.PowerWhitelistManager;
|
import android.os.Process;
|
||||||
import android.os.RemoteCallbackList;
|
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
-import android.os.ResultReceiver;
|
-import android.os.ResultReceiver;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
-import android.os.ShellCallback;
|
-import android.os.ShellCallback;
|
||||||
import android.os.SystemProperties;
|
import android.os.ShellCommand;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManagerInternal;
|
||||||
@@ -827,16 +826,13 @@ public boolean canPairWithoutPrompt(String packageName, String macAddress, int u
|
@@ -455,10 +455,12 @@ private void checkUsesFeature(String pkg, int userId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
- public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
- public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
||||||
- String[] args, ShellCallback callback, ResultReceiver resultReceiver)
|
- String[] args, ShellCallback callback, ResultReceiver resultReceiver)
|
||||||
- throws RemoteException {
|
- throws RemoteException {
|
||||||
- enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
|
- new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
|
||||||
-
|
|
||||||
- final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand(
|
|
||||||
- CompanionDeviceManagerService.this,
|
|
||||||
- mAssociationStore,
|
|
||||||
- mDevicePresenceMonitor);
|
|
||||||
- cmd.exec(this, in, out, err, args, callback, resultReceiver);
|
|
||||||
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
|
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
|
||||||
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
|
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
|
||||||
+ @NonNull String[] args) {
|
+ @NonNull String[] args) {
|
||||||
+ return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this,
|
+ return new ShellCmd()
|
||||||
+ mAssociationStore, mDevicePresenceMonitor)
|
|
||||||
+ .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
|
+ .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
|
||||||
+ err.getFileDescriptor(), args);
|
+ err.getFileDescriptor(), args);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
|
@ -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);
|
|
@ -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}) {
|
|
@ -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 */
|
|
@ -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);
|
|
||||||
+ }
|
|
||||||
}
|
|
@ -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)
|
|
@ -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>
|
|
@ -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
|
@ -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.
|
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
|
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/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;
|
fi;
|
||||||
|
|
||||||
if enterAndClear "build/soong"; then
|
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/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/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/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
|
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/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)
|
applyPatch "$DOS_PATCHES/android_frameworks_base/0008-Browser_No_Location.patch"; #Don't grant location permission to system browsers (GrapheneOS)
|
||||||
|
@ -66,8 +66,9 @@ patchWorkspaceReal() {
|
|||||||
verifyAllPlatformTags;
|
verifyAllPlatformTags;
|
||||||
gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview";
|
gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview";
|
||||||
|
|
||||||
#source build/envsetup.sh;
|
source build/envsetup.sh;
|
||||||
#repopick -ift twelve-bt-sbc-hd-dualchannel;
|
#repopick -ift twelve-bt-sbc-hd-dualchannel;
|
||||||
|
repopick -it S_asb_2024-06 -e 394523,394543;
|
||||||
|
|
||||||
sh "$DOS_SCRIPTS/Patch.sh";
|
sh "$DOS_SCRIPTS/Patch.sh";
|
||||||
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";
|
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";
|
||||||
|
@ -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.
|
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
|
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/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;
|
fi;
|
||||||
|
|
||||||
if enterAndClear "build/soong"; then
|
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)
|
applyPatch "$DOS_PATCHES/android_system_extras/0001-ext4_pad_filenames.patch"; #FBE: pad filenames more (GrapheneOS)
|
||||||
fi;
|
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
|
if enterAndClear "system/netd"; then
|
||||||
applyPatch "$DOS_PATCHES/android_system_netd/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS)
|
applyPatch "$DOS_PATCHES/android_system_netd/0001-Network_Permission.patch"; #Expose the NETWORK permission (GrapheneOS)
|
||||||
fi;
|
fi;
|
||||||
|
@ -162,7 +162,8 @@ patchWorkspaceReal() {
|
|||||||
verifyAllPlatformTags;
|
verifyAllPlatformTags;
|
||||||
gpgVerifyGitHead "$DOS_BUILD_BASE/external/chromium-webview";
|
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/Patch.sh";
|
||||||
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";
|
sh "$DOS_SCRIPTS_COMMON/Enable_Verity.sh";
|
||||||
|
@ -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)
|
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 '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/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;
|
fi;
|
||||||
|
|
||||||
if enterAndClear "build/soong"; then
|
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
|
sed -i -e '76,78d;' Android.bp; #fix compile under A13
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
if enterAndClear "frameworks/av"; then
|
|
||||||
git am $DOS_PATCHES/ASB-2023-10/av-*.patch;
|
|
||||||
fi;
|
|
||||||
|
|
||||||
if enterAndClear "frameworks/base"; then
|
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 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 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
|
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;
|
fi;
|
||||||
|
|
||||||
if enterAndClear "system/libfmq"; then
|
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;
|
fi;
|
||||||
|
|
||||||
if enterAndClear "system/sepolicy"; then
|
if enterAndClear "system/sepolicy"; then
|
||||||
|
Loading…
Reference in New Issue
Block a user