getAllPhoneAccountHandles() {
* when placing calls. The user may still need to enable the {@link PhoneAccount} within
* the phone app settings before the account is usable.
*
+ * Note: Each package is limited to 10 {@link PhoneAccount} registrations.
+ *
* A {@link SecurityException} will be thrown if an app tries to register a
* {@link PhoneAccountHandle} where the package name specified within
* {@link PhoneAccountHandle#getComponentName()} does not match the package name of the app.
+ *
+ * A {@link IllegalArgumentException} will be thrown if an app tries to register a
+ * {@link PhoneAccount} when the upper bound limit, 10, has already been reached.
*
* @param account The complete {@link PhoneAccount}.
*/
From 7d08d5473f0a90b1b4288eef550797b09a4ce72e Mon Sep 17 00:00:00 2001
From: Remi NGUYEN VAN
Date: Mon, 28 Feb 2022 18:02:27 +0900
Subject: [PATCH 046/208] Disallow PAP authentication when MPPE is requested
MPPE cannot work if PAP is used as authentication, so it is not useful
to allow PAP authentication when MPPE is enforced: establishing the
tunnel would fail anyway with "MPPE required, but MS-CHAP[v2] auth not
performed".
Also users enforcing MPPE may assume that this means PAP will not be
used for authentication, so without this change MPPE enforcement gives a
false sense of security, as PAP uses plain-text credentials.
Bug: 201660636
Test: atest VpnTest
Merged-In: Ie318d45fe44294e97cf38da7f1834cf014cb4417
Change-Id: Ie318d45fe44294e97cf38da7f1834cf014cb4417
(cherry picked from commit 997a4a39268b4f3af7ccc388269b5eb1972d3624)
(cherry picked from commit 4f319df8ff5a4b9f2bc62cb17df972e40b57fc81)
Merged-In: Ie318d45fe44294e97cf38da7f1834cf014cb4417
---
.../core/java/com/android/server/connectivity/Vpn.java | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 9edb0e440baa..8f9b5ca26e1b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2157,6 +2157,13 @@ public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
"usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400",
(profile.mppe ? "+mppe" : "nomppe"),
};
+ if (profile.mppe) {
+ // Disallow PAP authentication when MPPE is requested, as MPPE cannot work
+ // with PAP anyway, and users may not expect PAP (plain text) to be used when
+ // MPPE was requested.
+ mtpd = Arrays.copyOf(mtpd, mtpd.length + 1);
+ mtpd[mtpd.length - 1] = "-pap";
+ }
break;
case VpnProfile.TYPE_L2TP_IPSEC_PSK:
case VpnProfile.TYPE_L2TP_IPSEC_RSA:
From 9f6eba1abd4bded9235a6375fc2c64e90063e231 Mon Sep 17 00:00:00 2001
From: Eric Biggers
Date: Fri, 13 Aug 2021 13:37:55 -0700
Subject: [PATCH 047/208] [RESTRICT AUTOMERGE] StorageManagerService: don't
ignore failures to prepare user storage
We must never leave directories unencrypted.
Bug: 164488924
Bug: 224585613
Change-Id: I9a38ab5cca1ae9c9ebff81fca04615fd83ebe4b2
(cherry picked from commit 50946dd15fd14cbf92b5c7e32ac7a0f088b8b302)
Merged-In: I9a38ab5cca1ae9c9ebff81fca04615fd83ebe4b2
(cherry picked from commit ecffe3ecbf4cb01055bd2f852d95396f2475fc01)
Merged-In: I9a38ab5cca1ae9c9ebff81fca04615fd83ebe4b2
---
.../core/java/com/android/server/StorageManagerService.java | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 46538d0207f6..8f0964663dab 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3410,8 +3410,12 @@ private void prepareUserStorageInternal(String volumeUuid, int userId, int seria
mInstaller.tryMountDataMirror(volumeUuid);
}
}
- } catch (Exception e) {
+ } catch (RemoteException | Installer.InstallerException e) {
Slog.wtf(TAG, e);
+ // Make sure to re-throw this exception; we must not ignore failure
+ // to prepare the user storage as it could indicate that encryption
+ // wasn't successfully set up.
+ throw new RuntimeException(e);
}
}
From 76488e74dd83b996f3563e8d0a94e99d6c3c9740 Mon Sep 17 00:00:00 2001
From: Eric Biggers
Date: Mon, 24 Jan 2022 20:33:11 +0000
Subject: [PATCH 048/208] [RESTRICT AUTOMERGE] UserDataPreparer: reboot to
recovery if preparing user storage fails
StorageManager.prepareUserStorage() can throw an exception if a
directory cannot be encrypted, for example due to already being
nonempty. In this case, usage of the directory must not be allowed to
proceed. UserDataPreparer currently handles this by deleting the user's
directories, but the error is still ultimately suppressed and starting
the user is still allowed to proceed.
The correct behavior in this case is to reboot into recovery to ask the
user to factory reset the device. This is already what happens when
'init' fails to encrypt a directory with the system DE policy. However,
this was overlooked for the user directories. Start doing this.
Bug: 164488924
Bug: 224585613
Change-Id: Ib5e91d2510b25780d7a161b91b5cee2f6f7a2e54
(cherry picked from commit 5256365e65882b81509ec2f6b9dfe2dcf0025254)
Merged-In: Ib5e91d2510b25780d7a161b91b5cee2f6f7a2e54
(cherry picked from commit 69c3ce70c6dcabf57219d338af86e569ea672ef5)
Merged-In: Ib5e91d2510b25780d7a161b91b5cee2f6f7a2e54
---
.../core/java/com/android/server/pm/UserDataPreparer.java | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 045a295da965..504769064808 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -22,6 +22,7 @@
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.FileUtils;
+import android.os.RecoverySystem;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.SystemProperties;
@@ -115,6 +116,13 @@ private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, in
// Try one last time; if we fail again we're really in trouble
prepareUserDataLI(volumeUuid, userId, userSerial,
flags | StorageManager.FLAG_STORAGE_DE, false);
+ } else {
+ try {
+ Log.e(TAG, "prepareUserData failed", e);
+ RecoverySystem.rebootPromptAndWipeUserData(mContext, "prepareUserData failed");
+ } catch (IOException e2) {
+ throw new RuntimeException("error rebooting into recovery", e2);
+ }
}
}
}
From ac5d80fa9be8e42218f84de3ff8ed823cdf296bb Mon Sep 17 00:00:00 2001
From: Eric Biggers
Date: Fri, 4 Mar 2022 00:07:29 +0000
Subject: [PATCH 049/208] [RESTRICT AUTOMERGE] UserDataPreparer: reboot to
recovery for system user only
With the next CL, old devices might contain a combination of old users
with prepareUserStorage error checking disabled and new users with
prepareUserStorage error checking enabled. Factory resetting the whole
device when any user fails to prepare may be too aggressive. Also,
UserDataPreparer already destroys the affected user's storage when it
fails to prepare, which seems to be fairly effective at breaking things
for that user (absent proper error handling by upper layers).
Therefore, let's only factory reset the device if the failing user is
the system user.
Bug: 164488924
Bug: 224585613
Change-Id: Ia1db01ab4ec6b3b17d725f391c3500d92aa00f97
(cherry picked from commit 4c76da76c9831266e4e63c0618150bed10a929a7)
Merged-In: Ia1db01ab4ec6b3b17d725f391c3500d92aa00f97
(cherry picked from commit ecf569bd1623231984e9ec9823edb82f52d7846a)
Merged-In: Ia1db01ab4ec6b3b17d725f391c3500d92aa00f97
---
.../core/java/com/android/server/pm/UserDataPreparer.java | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index 504769064808..95482d7c7f1a 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -118,8 +118,11 @@ private void prepareUserDataLI(String volumeUuid, int userId, int userSerial, in
flags | StorageManager.FLAG_STORAGE_DE, false);
} else {
try {
- Log.e(TAG, "prepareUserData failed", e);
- RecoverySystem.rebootPromptAndWipeUserData(mContext, "prepareUserData failed");
+ Log.wtf(TAG, "prepareUserData failed for user " + userId, e);
+ if (userId == UserHandle.USER_SYSTEM) {
+ RecoverySystem.rebootPromptAndWipeUserData(mContext,
+ "prepareUserData failed for system user");
+ }
} catch (IOException e2) {
throw new RuntimeException("error rebooting into recovery", e2);
}
From 905f7f797f3008001ce604afd7d51dcd600cf398 Mon Sep 17 00:00:00 2001
From: Eric Biggers
Date: Fri, 4 Mar 2022 00:07:43 +0000
Subject: [PATCH 050/208] [RESTRICT AUTOMERGE] Ignore errors preparing user
storage for existing users
Unfortunately we can't rule out the existence of devices where the user
storage wasn't properly prepared, due to StorageManagerService
previously ignoring errors from mVold.prepareUserStorage, combined with
OEMs potentially creating files in per-user directories too early. And
forcing these broken devices to be factory reset upon taking an OTA is
not currently considered to be acceptable.
One option is to only check for prepareUserStorage errors on devices
that launched with T or later. However, this is a serious issue and it
would be strongly preferable to do more than that.
Therefore, this CL makes it so that errors are checked for all new
users, rather than all new devices. A field ignorePrepareStorageErrors
is added to the user record; it is only ever set to true implicitly,
when reading a user record from disk that lacks this field. This field
is used by StorageManagerService to decide whether to check for errors.
Bug: 164488924
Bug: 224585613
Test: Intentionally made a device affected by this issue by reverting
the CLs that introduced the error checks, and changing vold to
inject an error into prepareUserStorage. Then, flashed a build
with this CL without wiping userdata. The device still boots, as
expected, and the log shows that the error was intentionally
ignored. Tested that if a second user is added, the error is
*not* ignored and the second user's storage is destroyed before it
can be used. Finally, wiped the device and verified that it won't
boot up anymore, as expected since error checking is enabled for
the system user in that case.
Change-Id: I9bdd1a4bf5b14542adb901f264a91d489115c89b
(cherry picked from commit 60d8318c47b7b659716d71243d087b34ab327f64)
Merged-In: I9bdd1a4bf5b14542adb901f264a91d489115c89b
(cherry picked from commit e03e987337accde646e4e86c1fdfe02c0d78d743)
Merged-In: I9bdd1a4bf5b14542adb901f264a91d489115c89b
---
.../java/android/os/UserManagerInternal.java | 8 ++++
.../android/server/StorageManagerService.java | 11 ++++-
.../android/server/pm/UserManagerService.java | 42 +++++++++++++++++++
3 files changed, 60 insertions(+), 1 deletion(-)
diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java
index 38983488654e..502400dbd8ae 100644
--- a/services/core/java/android/os/UserManagerInternal.java
+++ b/services/core/java/android/os/UserManagerInternal.java
@@ -279,4 +279,12 @@ public abstract boolean isSettingRestrictedForUser(String setting, int userId, S
* Gets all {@link UserInfo UserInfos}.
*/
public abstract @NonNull UserInfo[] getUserInfos();
+
+ /**
+ * Returns {@code true} if the system should ignore errors when preparing
+ * the storage directories for the user with ID {@code userId}. This will
+ * return {@code false} for all new users; it will only return {@code true}
+ * for users that already existed on-disk from an older version of Android.
+ */
+ public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 8f0964663dab..780ecbf11f75 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3410,11 +3410,20 @@ private void prepareUserStorageInternal(String volumeUuid, int userId, int seria
mInstaller.tryMountDataMirror(volumeUuid);
}
}
- } catch (RemoteException | Installer.InstallerException e) {
+ } catch (Exception e) {
Slog.wtf(TAG, e);
// Make sure to re-throw this exception; we must not ignore failure
// to prepare the user storage as it could indicate that encryption
// wasn't successfully set up.
+ //
+ // Very unfortunately, these errors need to be ignored for broken
+ // users that already existed on-disk from older Android versions.
+ UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
+ if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
+ Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
+ + "; device may be insecure!");
+ return;
+ }
throw new RuntimeException(e);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a768e8e02911..9576dc567c3f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -198,6 +198,8 @@ public class UserManagerService extends IUserManager.Stub {
private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
"lastRequestQuietModeEnabledCall";
+ private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
+ "ignorePrepareStorageErrors";
private static final String ATTR_KEY = "key";
private static final String ATTR_VALUE_TYPE = "type";
private static final String ATTR_MULTIPLE = "m";
@@ -298,6 +300,14 @@ static class UserData {
private long mLastRequestQuietModeEnabledMillis;
+ /**
+ * {@code true} if the system should ignore errors when preparing the
+ * storage directories for this user. This is {@code false} for all new
+ * users; it will only be {@code true} for users that already existed
+ * on-disk from an older version of Android.
+ */
+ private boolean mIgnorePrepareStorageErrors;
+
void setLastRequestQuietModeEnabledMillis(long millis) {
mLastRequestQuietModeEnabledMillis = millis;
}
@@ -306,6 +316,14 @@ long getLastRequestQuietModeEnabledMillis() {
return mLastRequestQuietModeEnabledMillis;
}
+ boolean getIgnorePrepareStorageErrors() {
+ return mIgnorePrepareStorageErrors;
+ }
+
+ void setIgnorePrepareStorageErrors() {
+ mIgnorePrepareStorageErrors = true;
+ }
+
void clearSeedAccountData() {
seedAccountName = null;
seedAccountType = null;
@@ -2955,6 +2973,10 @@ void writeUserLP(UserData userData, OutputStream os)
serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
}
+ serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+ serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors()));
+ serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
+
serializer.endTag(null, TAG_USER);
serializer.endDocument();
@@ -3067,6 +3089,7 @@ UserData readUserLP(int id, InputStream is) throws IOException,
Bundle legacyLocalRestrictions = null;
RestrictionsSet localRestrictions = null;
Bundle globalRestrictions = null;
+ boolean ignorePrepareStorageErrors = true; // default is true for old users
XmlPullParser parser = Xml.newPullParser();
parser.setInput(is, StandardCharsets.UTF_8.name());
@@ -3158,6 +3181,11 @@ UserData readUserLP(int id, InputStream is) throws IOException,
if (type == XmlPullParser.TEXT) {
lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
}
+ } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText());
+ }
}
}
}
@@ -3185,6 +3213,9 @@ UserData readUserLP(int id, InputStream is) throws IOException,
userData.persistSeedData = persistSeedData;
userData.seedAccountOptions = seedAccountOptions;
userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
+ if (ignorePrepareStorageErrors) {
+ userData.setIgnorePrepareStorageErrors();
+ }
synchronized (mRestrictionsLock) {
if (baseRestrictions != null) {
@@ -4829,6 +4860,9 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println();
}
}
+
+ pw.println(" Ignore errors preparing storage: "
+ + userData.getIgnorePrepareStorageErrors());
}
}
pw.println();
@@ -5254,6 +5288,14 @@ public boolean hasUserRestriction(String restrictionKey, @UserIdInt int userId)
return allInfos;
}
}
+
+ @Override
+ public boolean shouldIgnorePrepareStorageErrors(int userId) {
+ synchronized (mUsersLock) {
+ UserData userData = mUsers.get(userId);
+ return userData != null && userData.getIgnorePrepareStorageErrors();
+ }
+ }
}
/**
From 05a1a227aa88272a2e112e30b2e9c651ed1c231a Mon Sep 17 00:00:00 2001
From: Eric Biggers
Date: Sat, 26 Mar 2022 01:08:07 +0000
Subject: [PATCH 051/208] [RESTRICT AUTOMERGE] Log to EventLog on
prepareUserStorage failure
Bug: 224585613
Change-Id: Id6dfb4f4c48d5cf4e71f54bdb6d0d6eea527caf5
(cherry picked from commit fbb632ea95ac5b6d9efa89e09d0988a9df4f19e4)
Merged-In: Id6dfb4f4c48d5cf4e71f54bdb6d0d6eea527caf5
(cherry picked from commit 0762961674f1454b7c7012a0ab53c427570e836c)
Merged-In: Id6dfb4f4c48d5cf4e71f54bdb6d0d6eea527caf5
---
.../core/java/com/android/server/StorageManagerService.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 780ecbf11f75..f34b56df35e8 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -132,6 +132,7 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.DataUnit;
+import android.util.EventLog;
import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
@@ -3411,6 +3412,7 @@ private void prepareUserStorageInternal(String volumeUuid, int userId, int seria
}
}
} catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "224585613", -1, "");
Slog.wtf(TAG, e);
// Make sure to re-throw this exception; we must not ignore failure
// to prepare the user storage as it could indicate that encryption
From 2ce42a764abee240686b6f19e2c2ef040c46a3a3 Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Wed, 7 Jul 2021 16:19:44 -0400
Subject: [PATCH 052/208] Crash invalid FGS notifications
Test: CTS, ActivityManagerProcessStateTest
Fixes: 191981182
Change-Id: I13a0202b25c8118db47edba11a93c1939c94b392
(cherry picked from commit 6f657f8f5b7d41af426d6cd8d60bfda6e12057c0)
(cherry picked from commit cb3c5c30092fb8527ff14118ccf04eae3a8363cb)
Merged-In: I13a0202b25c8118db47edba11a93c1939c94b392
---
.../server/notification/NotificationManagerService.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ddfe5b03d52a..8180c0404431 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -5811,8 +5811,10 @@ void enqueueNotificationInternal(final String pkg, final String opPkg, final int
// Fix the notification as best we can.
try {
fixNotification(notification, pkg, tag, id, userId);
-
} catch (Exception e) {
+ if (notification.isForegroundService()) {
+ throw new SecurityException("Invalid FGS notification", e);
+ }
Slog.e(TAG, "Cannot fix notification", e);
return;
}
From f80d4f6b63908738dad9e9bc778f60f5c3d54132 Mon Sep 17 00:00:00 2001
From: Jeff Chang
Date: Mon, 21 Feb 2022 17:42:22 +0800
Subject: [PATCH 053/208] [RESTRICT AUTOMERGE]Only allow system and same app to
apply relinquishTaskIdentity
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Any malicious application could hijack tasks by
android:relinquishTaskIdentity. This vulnerability can perform UI
spoofing or spy on user’s activities.
This CL limit the usage which only allow system and same app to apply
relinquishTaskIdentity. Based on the condition of updateIdentity from
Task#setIntent, update the intent with the parent's task together to
align with original code logic. Moreover, we shouldn't save launch
params for such tasks with null realActivity.
Bug: 185810717
Bug: 218243793
Test: atest IntentTests
atest ActivityStarterTests
atest TaskRecordTests
atest testSplitscreenPortraitAppOrientationRequests
Change-Id: I42c671e66c39c82be1dcef1f374d56d4593f9f57
(cherry picked from commit 7221a25a035bc7397492e15460b40395efce7023)
Merged-In: I42c671e66c39c82be1dcef1f374d56d4593f9f57
---
.../server/wm/LaunchParamsPersister.java | 3 +
.../core/java/com/android/server/wm/Task.java | 62 ++++++++++++++-----
.../android/server/wm/TaskRecordTests.java | 44 +++++++++++++
3 files changed, 92 insertions(+), 17 deletions(-)
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index a974332fd852..b037e59942cf 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -214,6 +214,9 @@ void saveTask(Task task) {
void saveTask(Task task, DisplayContent display) {
final ComponentName name = task.realActivity;
+ if (name == null) {
+ return;
+ }
final int userId = task.mUserId;
PersistableLaunchParams params;
ArrayMap map = mLaunchParamsMap.get(userId);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2da9c8db9ff8..1887cb73848b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -119,6 +119,7 @@
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -227,6 +228,11 @@ class Task extends WindowContainer {
// Do not move the stack as a part of reparenting
static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
+ /**
+ * Used to identify if the activity that is installed from device's system image.
+ */
+ boolean mIsEffectivelySystemApp;
+
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving
@@ -477,11 +483,24 @@ private boolean processActivity(ActivityRecord r,
if (r.finishing) return false;
- // Set this as the candidate root since it isn't finishing.
- mRoot = r;
+ if (mRoot == null || mRoot.finishing) {
+ // Set this as the candidate root since it isn't finishing.
+ mRoot = r;
+ }
- // Only end search if we are ignore relinquishing identity or we are not relinquishing.
- return ignoreRelinquishIdentity || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ final int uid = mRoot == r ? effectiveUid : r.info.applicationInfo.uid;
+ if (ignoreRelinquishIdentity
+ || (mRoot.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0
+ || (mRoot.info.applicationInfo.uid != Process.SYSTEM_UID
+ && !mRoot.info.applicationInfo.isSystemApp()
+ && mRoot.info.applicationInfo.uid != uid)) {
+ // No need to relinquish identity, end search.
+ return true;
+ }
+
+ // Relinquish to next activity
+ mRoot = r;
+ return false;
}
}
@@ -929,27 +948,35 @@ void setIntent(ActivityRecord r) {
* @param info The activity info which could be different from {@code r.info} if set.
*/
void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) {
- mCallingUid = r.launchedFromUid;
- mCallingPackage = r.launchedFromPackage;
- mCallingFeatureId = r.launchedFromFeatureId;
- setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
- setLockTaskAuth(r);
-
- final WindowContainer parent = getParent();
- if (parent != null) {
- final Task t = parent.asTask();
- if (t != null) {
- t.setIntent(r);
+ boolean updateIdentity = false;
+ if (this.intent == null) {
+ updateIdentity = true;
+ } else if (!mNeverRelinquishIdentity) {
+ final ActivityInfo activityInfo = info != null ? info : r.info;
+ updateIdentity = (effectiveUid == Process.SYSTEM_UID || mIsEffectivelySystemApp
+ || effectiveUid == activityInfo.applicationInfo.uid);
+ }
+ if (updateIdentity) {
+ mCallingUid = r.launchedFromUid;
+ mCallingPackage = r.launchedFromPackage;
+ mCallingFeatureId = r.launchedFromFeatureId;
+ setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
+ final WindowContainer parent = getParent();
+ if (parent != null) {
+ final Task t = parent.asTask();
+ if (t != null) {
+ t.setIntent(r);
+ }
}
}
+ setLockTaskAuth(r);
}
/** Sets the original intent, _without_ updating the calling uid or package. */
private void setIntent(Intent _intent, ActivityInfo info) {
final boolean isLeaf = isLeafTask();
if (intent == null) {
- mNeverRelinquishIdentity =
- (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
} else if (mNeverRelinquishIdentity && isLeaf) {
return;
}
@@ -962,6 +989,7 @@ private void setIntent(Intent _intent, ActivityInfo info) {
rootAffinity = affinity;
}
effectiveUid = info.applicationInfo.uid;
+ mIsEffectivelySystemApp = info.applicationInfo.isSystemApp();
stringName = null;
if (info.targetActivity == null) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index ddaa586fae8a..3be17b8fac19 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -616,6 +616,7 @@ public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
// one above as finishing.
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ task.effectiveUid = activity0.getUid();
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
activity1.finishing = true;
new ActivityBuilder(mService).setTask(task).build();
@@ -650,6 +651,7 @@ public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
// Set relinquishTaskIdentity for all activities in the task
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ task.effectiveUid = activity0.getUid();
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -802,6 +804,7 @@ public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
// Make the current root activity relinquish task identity
final ActivityRecord activity0 = task.getBottomMostActivity();
activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+ task.effectiveUid = activity0.getUid();
// Add an extra activity on top - this will be the new root
final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
// Add one more on top
@@ -896,6 +899,47 @@ public void testUpdateEffectiveIntent_allFinishing() {
verify(task).setIntent(eq(activity0));
}
+ /**
+ * Test {@link Task#updateEffectiveIntent()} when activity with relinquishTaskIdentity but
+ * another with different uid. This should make the task use the root activity when updating the
+ * intent.
+ */
+ @Test
+ public void testUpdateEffectiveIntent_relinquishingWithDifferentUid() {
+ final ActivityRecord activity0 = new ActivityBuilder(mService)
+ .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build();
+ final Task task = activity0.getTask();
+
+ // Add an extra activity on top
+ new ActivityBuilder(mService).setUid(11).setTask(task).build();
+
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity0));
+ }
+
+ /**
+ * Test {@link Task#updateEffectiveIntent()} with activities set as relinquishTaskIdentity.
+ * This should make the task use the topmost activity when updating the intent.
+ */
+ @Test
+ public void testUpdateEffectiveIntent_relinquishingMultipleActivities() {
+ final ActivityRecord activity0 = new ActivityBuilder(mService)
+ .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build();
+ final Task task = activity0.getTask();
+ task.effectiveUid = activity0.getUid();
+ // Add an extra activity on top
+ final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
+ activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
+
+ // Add an extra activity on top
+ final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
+
+ spyOn(task);
+ task.updateEffectiveIntent();
+ verify(task).setIntent(eq(activity2));
+ }
+
@Test
public void testSaveLaunchingStateWhenConfigurationChanged() {
LaunchParamsPersister persister = mService.mStackSupervisor.mLaunchParamsPersister;
From fd085b449206e0e750d509b971bed6f6b915df53 Mon Sep 17 00:00:00 2001
From: Wenhao Wang
Date: Wed, 2 Feb 2022 10:56:44 -0800
Subject: [PATCH 054/208] DO NOT MERGE Suppress notifications when device enter
lockdown
This CL makes the following modifcations:
1. Add LockPatternUtils.StrongAuthTracker to monitor
the lockdown mode status of the phone.
2. Call mListeners.notifyRemovedLocked with all the
notifications in the mNotificationList when entering
the lockdown mode.
3. Call mListeners.notifyPostedLocked with all the
notifications in the mNotificationList when exiting
the lockdown mode.
4. Dismiss the function calls of notifyPostedLocked,
notifyRemovedLocked, and notifyRankingUpdateLocked
during the lockdown mode.
The CL also adds corresponding tests.
Bug: 173721373
Test: atest NotificationManagerServiceTest
Test: atest NotificationListenersTest
Test: manually verify the paired device cannot receive
notifications when the host phone is in lockdown mode.
Ignore-AOSP-First: pending fix for a security issue.
Change-Id: I7e83544863eeadf8272b6ff8a9bb8136d6466203
Merged-In: I7e83544863eeadf8272b6ff8a9bb8136d6466203
(cherry picked from commit 3cb6842a053e236cc98d7616ba4433c31ffda3ac)
(cherry picked from commit 2e1c70b6b22422fb1f16be7add728327853f4618)
Merged-In: I7e83544863eeadf8272b6ff8a9bb8136d6466203
---
.../NotificationManagerService.java | 107 +++++++++++++-
.../tests/uiservicestests/AndroidManifest.xml | 1 +
.../NotificationListenersTest.java | 133 ++++++++++++++++++
.../NotificationManagerServiceTest.java | 66 ++++++++-
4 files changed, 302 insertions(+), 5 deletions(-)
create mode 100644 services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8180c0404431..5bd5c6067ea0 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -227,6 +227,7 @@
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.StatsEvent;
import android.util.TimeUtils;
import android.util.Xml;
@@ -258,6 +259,7 @@
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.TriPredicate;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.IoThread;
@@ -1729,6 +1731,54 @@ static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
return out;
}
+ protected class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+ SparseBooleanArray mUserInLockDownMode = new SparseBooleanArray();
+ boolean mIsInLockDownMode = false;
+
+ StrongAuthTracker(Context context) {
+ super(context);
+ }
+
+ private boolean containsFlag(int haystack, int needle) {
+ return (haystack & needle) != 0;
+ }
+
+ public boolean isInLockDownMode() {
+ return mIsInLockDownMode;
+ }
+
+ @Override
+ public synchronized void onStrongAuthRequiredChanged(int userId) {
+ boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mUserInLockDownMode.put(userId, userInLockDownModeNext);
+ boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1;
+
+ if (mIsInLockDownMode == isInLockDownModeNext) {
+ return;
+ }
+
+ if (isInLockDownModeNext) {
+ cancelNotificationsWhenEnterLockDownMode();
+ }
+
+ // When the mIsInLockDownMode is true, both notifyPostedLocked and
+ // notifyRemovedLocked will be dismissed. So we shall call
+ // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode
+ // as true and call postNotificationsWhenExitLockDownMode after we set
+ // mIsInLockDownMode as false.
+ mIsInLockDownMode = isInLockDownModeNext;
+
+ if (!isInLockDownModeNext) {
+ postNotificationsWhenExitLockDownMode();
+ }
+ }
+ }
+
+ private LockPatternUtils mLockPatternUtils;
+ private StrongAuthTracker mStrongAuthTracker;
+
public NotificationManagerService(Context context) {
this(context,
new NotificationRecordLoggerImpl(),
@@ -1754,6 +1804,11 @@ void setAudioManager(AudioManager audioMananger) {
mAudioManager = audioMananger;
}
+ @VisibleForTesting
+ void setStrongAuthTracker(StrongAuthTracker strongAuthTracker) {
+ mStrongAuthTracker = strongAuthTracker;
+ }
+
@VisibleForTesting
void setKeyguardManager(KeyguardManager keyguardManager) {
mKeyguardManager = keyguardManager;
@@ -1941,6 +1996,8 @@ void init(WorkerHandler handler, RankingHandler rankingHandler,
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mUiHandler = new Handler(UiThread.get().getLooper());
+ mLockPatternUtils = new LockPatternUtils(getContext());
+ mStrongAuthTracker = new StrongAuthTracker(getContext());
String[] extractorNames;
try {
extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
@@ -2137,7 +2194,8 @@ public void onStart() {
init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
- new NotificationListeners(AppGlobals.getPackageManager()),
+ new NotificationListeners(getContext(), mNotificationLock, mUserProfiles,
+ AppGlobals.getPackageManager()),
new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
AppGlobals.getPackageManager()),
new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
@@ -2387,6 +2445,7 @@ public void onBootPhase(int phase) {
bubbsExtractor.setShortcutHelper(mShortcutHelper);
}
registerNotificationPreferencesPullers();
+ mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
@@ -8627,6 +8686,29 @@ protected void unhideNotificationsForPackages(String[] pkgs) {
}
}
+ private void cancelNotificationsWhenEnterLockDownMode() {
+ synchronized (mNotificationLock) {
+ int numNotifications = mNotificationList.size();
+ for (int i = 0; i < numNotifications; i++) {
+ NotificationRecord rec = mNotificationList.get(i);
+ mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL,
+ rec.getStats());
+ }
+
+ }
+ }
+
+ private void postNotificationsWhenExitLockDownMode() {
+ synchronized (mNotificationLock) {
+ int numNotifications = mNotificationList.size();
+ for (int i = 0; i < numNotifications; i++) {
+ NotificationRecord rec = mNotificationList.get(i);
+ mListeners.notifyPostedLocked(rec, rec);
+ }
+
+ }
+ }
+
private void updateNotificationPulse() {
synchronized (mNotificationLock) {
updateLightsLocked();
@@ -8868,6 +8950,10 @@ private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo inf
rankings.toArray(new NotificationListenerService.Ranking[0]));
}
+ boolean isInLockDownMode() {
+ return mStrongAuthTracker.isInLockDownMode();
+ }
+
boolean hasCompanionDevice(ManagedServiceInfo info) {
if (mCompanionManager == null) {
mCompanionManager = getCompanionManager();
@@ -9448,8 +9534,9 @@ public class NotificationListeners extends ManagedServices {
private final ArraySet mLightTrimListeners = new ArraySet<>();
- public NotificationListeners(IPackageManager pm) {
- super(getContext(), mNotificationLock, mUserProfiles, pm);
+ public NotificationListeners(Context context, Object lock, UserProfiles userProfiles,
+ IPackageManager pm) {
+ super(context, lock, userProfiles, pm);
}
@Override
@@ -9583,8 +9670,12 @@ public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
* targetting <= O_MR1
*/
@GuardedBy("mNotificationLock")
- private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
+ void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
boolean notifyAllListeners) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
try {
// Lazily initialized snapshots of the notification.
StatusBarNotification sbn = r.getSbn();
@@ -9681,6 +9772,10 @@ private void updateUriPermissionsForActiveNotificationsLocked(
@GuardedBy("mNotificationLock")
public void notifyRemovedLocked(NotificationRecord r, int reason,
NotificationStats notificationStats) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
final StatusBarNotification sbn = r.getSbn();
// make a copy in case changes are made to the underlying Notification object
@@ -9726,6 +9821,10 @@ public void notifyRemovedLocked(NotificationRecord r, int reason,
*/
@GuardedBy("mNotificationLock")
public void notifyRankingUpdateLocked(List changedHiddenNotifications) {
+ if (isInLockDownMode()) {
+ return;
+ }
+
boolean isHiddenRankingUpdate = changedHiddenNotifications != null
&& changedHiddenNotifications.size() > 0;
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index 767857bf2de8..e8e3a8f84f21 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -33,6 +33,7 @@
+
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
new file mode 100644
index 000000000000..7244fcdda731
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.INotificationManager;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.service.notification.NotificationStats;
+import android.service.notification.StatusBarNotification;
+import android.testing.TestableContext;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
+
+import java.util.List;
+
+public class NotificationListenersTest extends UiServiceTestCase {
+
+ @Mock
+ private PackageManager mPm;
+ @Mock
+ private IPackageManager miPm;
+
+ @Mock
+ NotificationManagerService mNm;
+ @Mock
+ private INotificationManager mINm;
+ private TestableContext mContext = spy(getContext());
+
+ NotificationManagerService.NotificationListeners mListeners;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ getContext().setMockPackageManager(mPm);
+ doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
+
+ mListeners = spy(mNm.new NotificationListeners(
+ mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm));
+ when(mNm.getBinderService()).thenReturn(mINm);
+ }
+
+
+ @Test
+ public void testNotifyPostedLockedInLockdownMode() {
+ NotificationRecord r = mock(NotificationRecord.class);
+ NotificationRecord old = mock(NotificationRecord.class);
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ mListeners.notifyPostedLocked(r, old, true);
+ mListeners.notifyPostedLocked(r, old, false);
+ verify(r, atLeast(2)).getSbn();
+
+ // in the lockdown mode
+ reset(r);
+ reset(old);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ mListeners.notifyPostedLocked(r, old, true);
+ mListeners.notifyPostedLocked(r, old, false);
+ verify(r, never()).getSbn();
+ }
+
+ @Test
+ public void testnotifyRankingUpdateLockedInLockdownMode() {
+ List chn = mock(List.class);
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ mListeners.notifyRankingUpdateLocked(chn);
+ verify(chn, atLeast(1)).size();
+
+ // in the lockdown mode
+ reset(chn);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ mListeners.notifyRankingUpdateLocked(chn);
+ verify(chn, never()).size();
+ }
+
+ @Test
+ public void testNotifyRemovedLockedInLockdownMode() throws NoSuchFieldException {
+ NotificationRecord r = mock(NotificationRecord.class);
+ NotificationStats rs = mock(NotificationStats.class);
+ StatusBarNotification sbn = mock(StatusBarNotification.class);
+ FieldSetter.setField(mNm,
+ NotificationManagerService.class.getDeclaredField("mHandler"),
+ mock(NotificationManagerService.WorkerHandler.class));
+
+ // before the lockdown mode
+ when(mNm.isInLockDownMode()).thenReturn(false);
+ when(r.getSbn()).thenReturn(sbn);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ verify(r, atLeast(2)).getSbn();
+
+ // in the lockdown mode
+ reset(r);
+ reset(rs);
+ when(mNm.isInLockDownMode()).thenReturn(true);
+ when(r.getSbn()).thenReturn(sbn);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ mListeners.notifyRemovedLocked(r, 0, rs);
+ verify(r, never()).getSbn();
+ }
+}
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 6e8b1d91196c..f1d91e9daf8c 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -52,9 +52,12 @@
import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -398,8 +401,26 @@ private void setNotificationAssistantAccessGrantedCallback(
interface NotificationAssistantAccessGrantedCallback {
void onGranted(ComponentName assistant, int userId, boolean granted);
}
+
+ class StrongAuthTrackerFake extends NotificationManagerService.StrongAuthTracker {
+ private int mGetStrongAuthForUserReturnValue = 0;
+ StrongAuthTrackerFake(Context context) {
+ super(context);
+ }
+
+ public void setGetStrongAuthForUserReturnValue(int val) {
+ mGetStrongAuthForUserReturnValue = val;
+ }
+
+ @Override
+ public int getStrongAuthForUser(int userId) {
+ return mGetStrongAuthForUserReturnValue;
+ }
+ }
}
+ TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
+
private class TestableToastCallback extends ITransientNotification.Stub {
@Override
public void show(IBinder windowToken) {
@@ -516,6 +537,9 @@ null, new ComponentName(PKG, "test_class"),
mService.setAudioManager(mAudioManager);
+ mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext);
+ mService.setStrongAuthTracker(mStrongAuthTracker);
+
mShortcutHelper = mService.getShortcutHelper();
mShortcutHelper.setLauncherApps(mLauncherApps);
mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
@@ -7129,4 +7153,44 @@ public void testGetActiveNotification_filtersUsers() throws Exception {
}
}
}
-}
+
+ @Test
+ public void testStrongAuthTracker_isInLockDownMode() {
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertTrue(mStrongAuthTracker.isInLockDownMode());
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertFalse(mStrongAuthTracker.isInLockDownMode());
+ }
+
+ @Test
+ public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() {
+ // post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // when entering the lockdown mode, cancel the 2 notifications.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+ assertTrue(mStrongAuthTracker.isInLockDownMode());
+
+ // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN.
+ ArgumentCaptor captor = ArgumentCaptor.forClass(Integer.class);
+ verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any());
+ assertEquals(REASON_CANCEL_ALL, captor.getValue().intValue());
+
+ // exit lockdown mode.
+ mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0);
+ mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId());
+
+ // the notifyPostedLocked function is called twice.
+ verify(mListeners, times(2)).notifyPostedLocked(any(), any());
+ }
+}
\ No newline at end of file
From 98f8c51ad2bb81017ca0a673d90067a45158c449 Mon Sep 17 00:00:00 2001
From: Hui Yu
Date: Sat, 7 May 2022 21:43:23 -0700
Subject: [PATCH 055/208] Make sure callingPackage belongs to callingUid when
checking BG-FGS restrictions.
This is to stop spoofed packageName to pretend to be allowListed
packageName so it can bypass the BG-FGS restriction. This applies to
both BG-FGS while-in-use restriction and BG-FGS-start restriction
since these two restrictions are related.
Bug: 216695100
Bug: 215003903
Test: atest cts/tests/app/src/android/app/cts/ActivityManagerFgsBgStartTest.java#testSpoofPackageName
Change-Id: Ic14fc331a9b5fbdbcfe6e54a31c8b765513bfd89
Merged-In: Ic14fc331a9b5fbdbcfe6e54a31c8b765513bfd89
BYPASS_INCLUSIVE_LANGUAGE_REASON=Legacy API
(cherry picked from commit 023509e4871c0dafb842dc812bfa62e8d59cbfae)
Merged-In: Ic14fc331a9b5fbdbcfe6e54a31c8b765513bfd89
---
.../com/android/server/am/ActiveServices.java | 35 ++++++++++++++-----
1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index aa38fd1e6fc4..25c4844a2984 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5001,14 +5001,16 @@ private boolean shouldAllowWhileInUsePermissionInFgsLocked(String callingPackage
return true;
}
- if (mAm.mInternal.isTempAllowlistedForFgsWhileInUse(callingUid)) {
- return true;
- }
-
- final boolean isWhiteListedPackage =
- mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
- if (isWhiteListedPackage) {
- return true;
+ if (verifyPackage(callingPackage, callingUid)) {
+ final boolean isWhiteListedPackage =
+ mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
+ if (isWhiteListedPackage) {
+ return true;
+ }
+ } else {
+ EventLog.writeEvent(0x534e4554, "215003903", callingUid,
+ "callingPackage:" + callingPackage + " does not belong to callingUid:"
+ + callingUid);
}
// Is the calling UID a device owner app?
@@ -5047,4 +5049,21 @@ private void resetFgsRestrictionLocked(ServiceRecord r) {
r.mAllowWhileInUsePermissionInFgs = false;
r.mLastSetFgsRestrictionTime = 0;
}
+
+ /**
+ * Checks if a given packageName belongs to a given uid.
+ * @param packageName the package of the caller
+ * @param uid the uid of the caller
+ * @return true or false
+ */
+ private boolean verifyPackage(String packageName, int uid) {
+ if (uid == ROOT_UID || uid == SYSTEM_UID) {
+ //System and Root are always allowed
+ return true;
+ }
+ final int userId = UserHandle.getUserId(uid);
+ final int packageUid = mAm.getPackageManagerInternalLocked()
+ .getPackageUid(packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+ return UserHandle.isSameApp(uid, packageUid);
+ }
}
From f05af87c97bb36016e83f0df3db21d8d358ec9e9 Mon Sep 17 00:00:00 2001
From: lucaslin
Date: Wed, 30 Mar 2022 20:42:43 +0800
Subject: [PATCH 056/208] Clear mInterface before calling resetIkeState()
Clear mInterface before calling resetIkeState() in
onDefaultNetworkChanged().
resetIkeState() will trigger interfaceRemoved() to be called.
If mInterface is set, interfaceRemoved() will clear
Ikev2VpnRunner which makes VPN disconnect.
This issue can be reproduced when device establishes VPN
connection with mobile data first then connects to wifi.
In this case, onLost() for mobile data will not be called
because there is a new network(wifi) can satisfy the request,
so only onAvailable() for wifi will be called.
Which means onSessionLost() will not be called and only
onDefaultNetworkChanged() will be called, which makes that
mInterface is not cleared before interfaceRemoved() is called.
Bug: 219546241
Test: Check if VPN is still there when establishing VPN with
mobile data first, then connect to wifi and disconnect
wifi.
Change-Id: I7f9a1d9afd2a40762e9fac68edf1fb8ae75df8bc
(cherry picked from commit 520cc2fde363dd038911b98b8b46259faf58a659)
Merged-In: I7f9a1d9afd2a40762e9fac68edf1fb8ae75df8bc
(cherry picked from commit 65d44b93bb99eae441ebf5bf1afb4efd00074758)
Merged-In: I7f9a1d9afd2a40762e9fac68edf1fb8ae75df8bc
---
services/core/java/com/android/server/connectivity/Vpn.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8f9b5ca26e1b..fd5b46cd0ff7 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2523,6 +2523,9 @@ public void onDefaultNetworkChanged(@NonNull Network network) {
return; // VPN has been shut down.
}
+ // Clear mInterface to prevent Ikev2VpnRunner being cleared when
+ // interfaceRemoved() is called.
+ mInterface = null;
// Without MOBIKE, we have no way to seamlessly migrate. Close on old
// (non-default) network, and start the new one.
resetIkeState();
From 11c5d57eff899f2194f26dac92b541f86372f3ed Mon Sep 17 00:00:00 2001
From: Raphael Kim
Date: Fri, 22 Apr 2022 00:32:08 +0000
Subject: [PATCH 057/208] Remove package title from notification access
confirmation intent
Bug: 228178437
Test: Manually confirmed on an application
Change-Id: Idad6dc0c71d7b39de0bd9e4ad922b5e6020a6184
Merged-In: Idad6dc0c71d7b39de0bd9e4ad922b5e6020a6184
(cherry picked from commit 51d47ec7c875cf964f46965a27a5d36343ea999d)
Merged-In: Idad6dc0c71d7b39de0bd9e4ad922b5e6020a6184
---
...ificationAccessConfirmationActivityContract.java | 10 ++++++----
.../companion/CompanionDeviceManagerService.java | 13 ++-----------
2 files changed, 8 insertions(+), 15 deletions(-)
diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
index 4ce6f609ef73..fdf0e9046eef 100644
--- a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
+++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
@@ -17,6 +17,7 @@
package com.android.internal.notification;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
public final class NotificationAccessConfirmationActivityContract {
@@ -25,13 +26,14 @@ public final class NotificationAccessConfirmationActivityContract {
"com.android.settings.notification.NotificationAccessConfirmationActivity");
public static final String EXTRA_USER_ID = "user_id";
public static final String EXTRA_COMPONENT_NAME = "component_name";
- public static final String EXTRA_PACKAGE_TITLE = "package_title";
- public static Intent launcherIntent(int userId, ComponentName component, String packageTitle) {
+ /**
+ * Creates a launcher intent for NotificationAccessConfirmationActivity.
+ */
+ public static Intent launcherIntent(Context context, int userId, ComponentName component) {
return new Intent()
.setComponent(COMPONENT_NAME)
.putExtra(EXTRA_USER_ID, userId)
- .putExtra(EXTRA_COMPONENT_NAME, component)
- .putExtra(EXTRA_PACKAGE_TITLE, packageTitle);
+ .putExtra(EXTRA_COMPONENT_NAME, component);
}
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ad91924c1e63..9f503419a7cf 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -43,7 +43,6 @@
import android.content.SharedPreferences;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.net.NetworkPolicyManager;
import android.os.Binder;
@@ -385,20 +384,12 @@ public PendingIntent requestNotificationAccess(ComponentName component)
String callingPackage = component.getPackageName();
checkCanCallNotificationApi(callingPackage);
int userId = getCallingUserId();
- String packageTitle = BidiFormatter.getInstance().unicodeWrap(
- getPackageInfo(callingPackage, userId)
- .applicationInfo
- .loadSafeLabel(getContext().getPackageManager(),
- PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
- PackageItemInfo.SAFE_LABEL_FLAG_TRIM
- | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE)
- .toString());
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
- userId, component, packageTitle),
+ getContext(), userId, component),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT,
null /* options */,
From 64cfbc7f08af1f359b61ed57061f5ab561cc82c0 Mon Sep 17 00:00:00 2001
From: Jeff Chang
Date: Fri, 27 May 2022 11:58:11 +0800
Subject: [PATCH 058/208] [RESTRICT AUTOMERGE]Prevent set intent on non-leaf
tasks
The root task was created with null intent, but the intent,
resize mode and other information were updated from child tasks,
which sets the split-screen-secondary root task to unresizable.
This CL is back porting from f666e494af to prevent setting the
split-screen-secondary root task to unresizable.
Bug: 230435065
Bug: 185810717
Test: atest IntentTests
atest ActivityStarterTests
atest TaskRecordTests
atest testSplitscreenPortraitAppOrientationRequests
Change-Id: I856d66371ac121f681958a7129527f18a5357d0f
(cherry picked from commit c5aaf99df5656fde68a4aaf2801fe30b0f5e44ae)
Merged-In: I856d66371ac121f681958a7129527f18a5357d0f
---
services/core/java/com/android/server/wm/Task.java | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1887cb73848b..0d1a3436d4cc 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -961,27 +961,20 @@ void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo
mCallingPackage = r.launchedFromPackage;
mCallingFeatureId = r.launchedFromFeatureId;
setIntent(intent != null ? intent : r.intent, info != null ? info : r.info);
- final WindowContainer parent = getParent();
- if (parent != null) {
- final Task t = parent.asTask();
- if (t != null) {
- t.setIntent(r);
- }
- }
}
setLockTaskAuth(r);
}
/** Sets the original intent, _without_ updating the calling uid or package. */
private void setIntent(Intent _intent, ActivityInfo info) {
- final boolean isLeaf = isLeafTask();
+ if (!isLeafTask()) return;
if (intent == null) {
mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
- } else if (mNeverRelinquishIdentity && isLeaf) {
+ } else if (mNeverRelinquishIdentity) {
return;
}
- affinity = isLeaf ? info.taskAffinity : null;
+ affinity = info.taskAffinity;
if (intent == null) {
// If this task already has an intent associated with it, don't set the root
// affinity -- we don't want it changing after initially set, but the initially
From 53607b12e0deef0b769abf121c981b0905a65174 Mon Sep 17 00:00:00 2001
From: chiachangwang
Date: Thu, 2 Jun 2022 10:22:20 +0000
Subject: [PATCH 059/208] Stop using invalid URL to prevent unexpected crash
Verify the input PAC Uri before performing follow-up actions.
Check if the URL is a valid URL to filter some invalid URLs since
these invalid URLs could not fall into any subclass of existing
URLConnections. When the PAC Uri is other invalid URL scheme, it
will cause an UnsupportedOperationException if there is no proper
subclass that implements the openConnection() method.
A malformed URL may crash the system.
Even it's a valid URL, some subclasses(e.g. JarURLConnection)
may not have openConnection() implemented. It will also hit the
problem, so convert the possbile exception from openConnection()
to re-throw it to IOException which is handled in the existing
code.
Bug: 219498290
Test: atest FrameworksNetTests CtsNetTestCases
Test: Test with malformed URL
Merged-In: I22903414380b62051f514e43b93af992f45740b4
Merged-In: I2abff75ec59a17628ef006aad348c53fadbed076
Change-Id: I4d6cec1da9cf3f70dec0dcf4223254d3da4f30a3
(cherry picked from commit 6390b37a3b32fc7583154d53fda3af8fbd95f59f)
(cherry picked from commit 6d6f4106948bbad67b9845603392d084078997c4)
Merged-In: I4d6cec1da9cf3f70dec0dcf4223254d3da4f30a3
---
.../server/connectivity/PacManager.java | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index f6ce2dc68b99..621c9c71df58 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -37,6 +37,7 @@
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
+import android.webkit.URLUtil;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.TrafficStatsConstants;
@@ -215,8 +216,22 @@ synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
* @throws IOException if the URL is malformed, or the PAC file is too big.
*/
private static String get(Uri pacUri) throws IOException {
- URL url = new URL(pacUri.toString());
- URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+ if (!URLUtil.isValidUrl(pacUri.toString())) {
+ throw new IOException("Malformed URL:" + pacUri);
+ }
+
+ final URL url = new URL(pacUri.toString());
+ URLConnection urlConnection;
+ try {
+ urlConnection = url.openConnection(java.net.Proxy.NO_PROXY);
+ // Catch the possible exceptions and rethrow as IOException to not to crash the system
+ // for illegal input.
+ } catch (IllegalArgumentException e) {
+ throw new IOException("Incorrect proxy type for " + pacUri);
+ } catch (UnsupportedOperationException e) {
+ throw new IOException("Unsupported URL connection type for " + pacUri);
+ }
+
long contentLength = -1;
try {
contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length"));
From b17f4b0eee4ce0596581aca37c607dac9b3e06b5 Mon Sep 17 00:00:00 2001
From: Makoto Onuki
Date: Tue, 19 Apr 2022 10:54:18 -0700
Subject: [PATCH 060/208] Only allow the system server to connect to sync
adapters
Bug: 203229608
Test: Manual test with changing the check logic + debug log
Change-Id: If18009f61360564d02dcda9b1e5fa15685e3250f
(cherry picked from commit 58270527d11ac7e5f07d337a402d8edf046a63ee)
(cherry picked from commit 7d1397a54475ed7fee632339ef7c60b432f0fbff)
Merged-In: If18009f61360564d02dcda9b1e5fa15685e3250f
---
.../content/AbstractThreadedSyncAdapter.java | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index a086a308d0d9..da4ecdd8c1f2 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -21,6 +21,7 @@
import android.accounts.Account;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -171,8 +172,20 @@ private Account toSyncKey(Account account) {
}
private class ISyncAdapterImpl extends ISyncAdapter.Stub {
+ private boolean isCallerSystem() {
+ final long callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ android.util.EventLog.writeEvent(0x534e4554, "203229608", -1, "");
+ return false;
+ }
+ return true;
+ }
+
@Override
public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) {
+ if (!isCallerSystem()) {
+ return;
+ }
Handler.getMain().sendMessage(obtainMessage(
AbstractThreadedSyncAdapter::handleOnUnsyncableAccount,
AbstractThreadedSyncAdapter.this, cb));
@@ -181,12 +194,16 @@ public void onUnsyncableAccount(ISyncAdapterUnsyncableAccountCallback cb) {
@Override
public void startSync(ISyncContext syncContext, String authority, Account account,
Bundle extras) {
+ if (!isCallerSystem()) {
+ return;
+ }
if (ENABLE_LOG) {
if (extras != null) {
extras.size(); // Unparcel so its toString() will show the contents.
}
Log.d(TAG, "startSync() start " + authority + " " + account + " " + extras);
}
+
try {
final SyncContext syncContextClient = new SyncContext(syncContext);
@@ -242,6 +259,9 @@ public void startSync(ISyncContext syncContext, String authority, Account accoun
@Override
public void cancelSync(ISyncContext syncContext) {
+ if (!isCallerSystem()) {
+ return;
+ }
try {
// synchronize to make sure that mSyncThreads doesn't change between when we
// check it and when we use it
From bd1cab7e4bf38d76967eb8adc89c0fa4689292ad Mon Sep 17 00:00:00 2001
From: Manjeet Rulhania
Date: Thu, 28 Apr 2022 21:50:25 +0000
Subject: [PATCH 061/208] Fix duplicate permission privilege escalation
Duplicate permissions definition with different group allows
privilege permission escalation to a different permission group.
Android studio and gradle plugin does not allow duplicate
permissions with different attributes, these tools only allow
if duplicate permissions are exact copies.
Also platform stores permissions in map at multiple places with
permission name as key. This suggests that we can disallow
duplicate permissions during package install/update
Bug: 213323615
Test: AppSecurityTests
Change-Id: I1910dca44104e35a57eba4acfa8188cd9b8626ac
Merged-Id: I34120fff2ec2a158dfa55779d2afd4bbd49487ff
Merged-In: I9bc839836786a0876e67fd73c05f8944bb532249
(cherry picked from commit f9a9dc720c151ce9d8a2bba6f5400f5a8f759b2d)
Merged-In: I1910dca44104e35a57eba4acfa8188cd9b8626ac
---
.../pm/parsing/ParsingPackageUtils.java | 8 +++
.../component/ParsedPermissionUtils.java | 49 +++++++++++++++++++
2 files changed, 57 insertions(+)
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index a56a3ea9b2f6..e4fd59c01eac 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -21,6 +21,7 @@
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
@@ -778,6 +779,13 @@ private ParseResult parseBaseApkTags(ParseInput input, ParsingPa
);
}
+ if (ParsedPermissionUtils.declareDuplicatePermission(pkg)) {
+ return input.error(
+ INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Found duplicate permission with a different attribute value."
+ );
+ }
+
convertNewPermissions(pkg);
convertSplitPermissions(pkg);
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index 1884a1e27832..9a6742c68ab4 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -22,6 +22,8 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.util.ArrayMap;
+import android.util.EventLog;
import android.util.Slog;
import com.android.internal.R;
@@ -32,6 +34,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
/** @hide */
public class ParsedPermissionUtils {
@@ -207,4 +211,49 @@ public static ParseResult parsePermissionGroup(ParsingPac
return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permissionGroup,
input);
}
+
+ /**
+ * Determines if a duplicate permission is malformed .i.e. defines different protection level
+ * or group.
+ */
+ private static boolean isMalformedDuplicate(ParsedPermission p1, ParsedPermission p2) {
+ // Since a permission tree is also added as a permission with normal protection
+ // level, we need to skip if the parsedPermission is a permission tree.
+ if (p1 == null || p2 == null || p1.isTree() || p2.isTree()) {
+ return false;
+ }
+
+ if (p1.getProtectionLevel() != p2.getProtectionLevel()) {
+ return true;
+ }
+ if (!Objects.equals(p1.getGroup(), p2.getGroup())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the package declares malformed duplicate permissions.
+ */
+ public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) {
+ final List permissions = pkg.getPermissions();
+ final int size = permissions.size();
+ if (size > 0) {
+ final ArrayMap checkDuplicatePerm = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ final ParsedPermission parsedPermission = permissions.get(i);
+ final String name = parsedPermission.getName();
+ final ParsedPermission perm = checkDuplicatePerm.get(name);
+ if (isMalformedDuplicate(parsedPermission, perm)) {
+ // Fix for b/213323615
+ EventLog.writeEvent(0x534e4554, "213323615",
+ "The package " + pkg.getPackageName() + " seems malicious");
+ return true;
+ }
+ checkDuplicatePerm.put(name, parsedPermission);
+ }
+ }
+ return false;
+ }
}
From afddff33b9f2b0d8d5db7512d84ef21668e1a6c5 Mon Sep 17 00:00:00 2001
From: Steven Moreland
Date: Wed, 30 Mar 2022 21:46:29 +0000
Subject: [PATCH 062/208] Parcel: recycle recycles
Before, it was like getting a used pan with food stuck on it. We run
a clean ship here. You want a Parcel? You get a fresh Parcel. When
we recycle a Parcel, we do a real clean-up job. Air freshener. All
bits brushed over. These Parcel objects are clean as heck now!
(specifically cleans mClassCookies)
Bug: 208279300
Test: build
Merged-In: I250872f5c6796bb64e2dc68008154c0e90feb218
Change-Id: I250872f5c6796bb64e2dc68008154c0e90feb218
(cherry picked from commit 46770fa49c9a5e51a5ea5a3afc7aab0dba2e59bd)
(cherry picked from commit b5c79e141a81fa86fc834980d46886ac3c86ab11)
Merged-In: I250872f5c6796bb64e2dc68008154c0e90feb218
---
core/java/android/os/Parcel.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index e5bab6fc9230..5a4b22b8a91b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -443,6 +443,7 @@ public static Parcel obtain() {
*/
public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
+ mClassCookies = null;
freeBuffer();
final Parcel[] pool;
From 269552610f03b338383ebb4426bbb36f8f41e222 Mon Sep 17 00:00:00 2001
From: Manjeet Rulhania
Date: Thu, 30 Jun 2022 22:09:09 +0000
Subject: [PATCH 063/208] Remove package name from SafetyNet logs
Bug: 213323615
Test: AppSecurityTests
Change-Id: I993832e148636f1795ffe393c6dc74a08b9442f8
Merged-In: I8f823487ca16861a35135cfc3383fa2ce8258017
Merged-In: I4b61d13256ce0bfb8fc9d21db52ee78ce2097f14
(cherry picked from commit bbe2a118277d9b225a272c53e509fdeb2fe0a993)
Merged-In: I993832e148636f1795ffe393c6dc74a08b9442f8
---
.../content/pm/parsing/component/ParsedPermissionUtils.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index 9a6742c68ab4..fa7cfceb1a4c 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -247,8 +247,7 @@ public static boolean declareDuplicatePermission(@NonNull ParsingPackage pkg) {
final ParsedPermission perm = checkDuplicatePerm.get(name);
if (isMalformedDuplicate(parsedPermission, perm)) {
// Fix for b/213323615
- EventLog.writeEvent(0x534e4554, "213323615",
- "The package " + pkg.getPackageName() + " seems malicious");
+ EventLog.writeEvent(0x534e4554, "213323615");
return true;
}
checkDuplicatePerm.put(name, parsedPermission);
From 9e399bb1963912b7ecf91d657fb88a4bd951b6fe Mon Sep 17 00:00:00 2001
From: Adrian Roos
Date: Wed, 16 Feb 2022 18:57:24 +0100
Subject: [PATCH 064/208] Restrict getInputMethodWindowVisibleHeight
Make sure only the app currently interacting with the IME can
query this, and restrict the API to apps targeting SDKs before T
Fixes: 204906124
Test: atest 'InputMethodManagerTest#getInputMethodWindowVisibleHeight_returnsZeroIfNotFocused'
Change-Id: If1da19a3dd8c29542afc970b4b201d87547c27a9
Merged-In: If1da19a3dd8c29542afc970b4b201d87547c27a9
(cherry picked from commit fd7847b53344edb46d0b62fbdfb3f5b12ba6ac9e)
Merged-In: If1da19a3dd8c29542afc970b4b201d87547c27a9
---
.../view/inputmethod/InputMethodManager.java | 2 +-
.../internal/view/IInputMethodManager.aidl | 2 +-
.../InputMethodManagerService.java | 69 ++++++++++++++-----
.../MultiClientInputMethodManagerService.java | 2 +-
4 files changed, 55 insertions(+), 20 deletions(-)
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 5f8b13b5b548..7b2ebde70e5f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2957,7 +2957,7 @@ public Map> getShortcutInputMethodsAnd
@UnsupportedAppUsage
public int getInputMethodWindowVisibleHeight() {
try {
- return mService.getInputMethodWindowVisibleHeight();
+ return mService.getInputMethodWindowVisibleHeight(mClient);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index a1cbd3fcae79..629d92927237 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -67,7 +67,7 @@ interface IInputMethodManager {
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this.
- int getInputMethodWindowVisibleHeight();
+ int getInputMethodWindowVisibleHeight(in IInputMethodClient client);
void reportActivityView(in IInputMethodClient parentClient, int childDisplayId,
in float[] matrixValues);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3e7437d1ee7e..eca500ec612b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -102,6 +102,7 @@
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.ContextThemeWrapper;
import android.view.DisplayInfo;
import android.view.IWindowManager;
@@ -317,6 +318,8 @@ private static final class DebugFlags {
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager;
+ private final SparseBooleanArray mLoggedDeniedGetInputMethodWindowVisibleHeightForUid =
+ new SparseBooleanArray(0);
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
@@ -1409,6 +1412,13 @@ public void onFinishPackageChanges() {
clearPackageChangeState();
}
+ @Override
+ public void onUidRemoved(int uid) {
+ synchronized (mMethodMap) {
+ mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.delete(uid);
+ }
+ }
+
private void clearPackageChangeState() {
// No need to lock them because we access these fields only on getRegisteredHandler().
mChangedPackages.clear();
@@ -3185,20 +3195,8 @@ public boolean showSoftInput(IInputMethodClient client, IBinder windowToken, int
}
final long ident = Binder.clearCallingIdentity();
try {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- final ClientState cs = mClients.get(client.asBinder());
- if (cs == null) {
- throw new IllegalArgumentException("unknown client " + client.asBinder());
- }
- if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
- cs.selfReportedDisplayId)) {
- Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
- return false;
- }
+ if (!canInteractWithImeLocked(uid, client, "showSoftInput")) {
+ return false;
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(windowToken, flags, resultReceiver,
@@ -3979,9 +3977,46 @@ public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[]
* @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
*/
@Override
- public int getInputMethodWindowVisibleHeight() {
- // TODO(yukawa): Should we verify the display ID?
- return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
+ @Deprecated
+ public int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) {
+ int callingUid = Binder.getCallingUid();
+ return Binder.withCleanCallingIdentity(() -> {
+ final int curTokenDisplayId;
+ synchronized (mMethodMap) {
+ if (!canInteractWithImeLocked(callingUid, client,
+ "getInputMethodWindowVisibleHeight")) {
+ if (!mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.get(callingUid)) {
+ EventLog.writeEvent(0x534e4554, "204906124", callingUid, "");
+ mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.put(callingUid, true);
+ }
+ return 0;
+ }
+ // This should probably use the caller's display id, but because this is unsupported
+ // and maintained only for compatibility, there's no point in fixing it.
+ curTokenDisplayId = mCurTokenDisplayId;
+ }
+ return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
+ });
+ }
+
+ private boolean canInteractWithImeLocked(int callingUid, IInputMethodClient client,
+ String method) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ final ClientState cs = mClients.get(client.asBinder());
+ if (cs == null) {
+ throw new IllegalArgumentException("unknown client " + client.asBinder());
+ }
+ if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
+ cs.selfReportedDisplayId)) {
+ Slog.w(TAG, "Ignoring " + method + " of uid " + callingUid + ": " + client);
+ return false;
+ }
+ }
+ return true;
}
@Override
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 19dff9807075..3429e7bb6bba 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1754,7 +1754,7 @@ public void setAdditionalInputMethodSubtypes(String imiId, InputMethodSubtype[]
@BinderThread
@Override
- public int getInputMethodWindowVisibleHeight() {
+ public int getInputMethodWindowVisibleHeight(IInputMethodClient client) {
reportNotSupported();
return 0;
}
From 31e8422115138d4fa8da63be16ca97ebe723e436 Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Fri, 1 Jul 2022 09:49:12 -0400
Subject: [PATCH 065/208] Limit the number of concurrently snoozed
notifications
Test: atest FrameworksUiServicesTests
Bug: 234441463
Change-Id: I005b43979d1c708fd505c8b33ae0c8cb03ddbb35
Merged-In: I005b43979d1c708fd505c8b33ae0c8cb03ddbb35
(cherry picked from commit 7c38394ae9c69620499a87e629edae4fe0ac4edc)
(cherry picked from commit 455a525421ea3748172d84a2529b9d993491a28f)
Merged-In: I005b43979d1c708fd505c8b33ae0c8cb03ddbb35
---
.../NotificationManagerService.java | 19 +++--
.../server/notification/SnoozeHelper.java | 11 +++
.../NotificationManagerServiceTest.java | 83 +++++++++++++++++--
.../server/notification/SnoozeHelperTest.java | 17 ++++
4 files changed, 116 insertions(+), 14 deletions(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5bd5c6067ea0..dd8f3e11b575 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -6335,6 +6335,7 @@ public void run() {
@GuardedBy("mNotificationLock")
void snoozeLocked(NotificationRecord r) {
+ final List recordsToSnooze = new ArrayList<>();
if (r.getSbn().isGroup()) {
final List groupNotifications =
findCurrentAndSnoozedGroupNotificationsLocked(
@@ -6343,8 +6344,8 @@ void snoozeLocked(NotificationRecord r) {
if (r.getNotification().isGroupSummary()) {
// snooze all children
for (int i = 0; i < groupNotifications.size(); i++) {
- if (mKey != groupNotifications.get(i).getKey()) {
- snoozeNotificationLocked(groupNotifications.get(i));
+ if (!mKey.equals(groupNotifications.get(i).getKey())) {
+ recordsToSnooze.add(groupNotifications.get(i));
}
}
} else {
@@ -6354,8 +6355,8 @@ void snoozeLocked(NotificationRecord r) {
if (groupNotifications.size() == 2) {
// snooze summary and the one child
for (int i = 0; i < groupNotifications.size(); i++) {
- if (mKey != groupNotifications.get(i).getKey()) {
- snoozeNotificationLocked(groupNotifications.get(i));
+ if (!mKey.equals(groupNotifications.get(i).getKey())) {
+ recordsToSnooze.add(groupNotifications.get(i));
}
}
}
@@ -6363,7 +6364,15 @@ void snoozeLocked(NotificationRecord r) {
}
}
// snooze the notification
- snoozeNotificationLocked(r);
+ recordsToSnooze.add(r);
+
+ if (mSnoozeHelper.canSnooze(recordsToSnooze.size())) {
+ for (int i = 0; i < recordsToSnooze.size(); i++) {
+ snoozeNotificationLocked(recordsToSnooze.get(i));
+ }
+ } else {
+ Log.w(TAG, "Cannot snooze " + r.getKey() + ": too many snoozed notifications");
+ }
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index da472be81156..a29ac131f94c 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -60,6 +60,8 @@
public class SnoozeHelper {
public static final String XML_SNOOZED_NOTIFICATION_VERSION = "1";
+ static final int CONCURRENT_SNOOZE_LIMIT = 500;
+
protected static final String XML_TAG_NAME = "snoozed-notifications";
private static final String XML_SNOOZED_NOTIFICATION = "notification";
@@ -132,6 +134,15 @@ void cleanupPersistedContext(String key){
}
}
+ protected boolean canSnooze(int numberToSnooze) {
+ synchronized (mLock) {
+ if ((mPackages.size() + numberToSnooze) > CONCURRENT_SNOOZE_LIMIT) {
+ return false;
+ }
+ }
+ return true;
+ }
+
@NonNull
protected Long getSnoozeTimeForUnpostedNotification(int userId, String pkg, String key) {
Long time = null;
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 f1d91e9daf8c..88d7680d9236 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -2795,20 +2795,81 @@ public void testHasCompanionDevice_noService() {
assertFalse(mService.hasCompanionDevice(mListener));
}
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_singleNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ mService.addNotification(notification);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(1)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notification.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertEquals(1, mService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord notificationChild = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", false);
+ mService.addNotification(notification);
+ mService.addNotification(notificationChild);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(2)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notificationChild.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertEquals(2, mService.getNotificationRecordCount());
+ }
+
+ @Test
+ public void testSnoozeRunnable_tooManySnoozed_summaryNotification() {
+ final NotificationRecord notification = generateNotificationRecord(
+ mTestNotificationChannel, 1, "group", true);
+ final NotificationRecord notificationChild = generateNotificationRecord(
+ mTestNotificationChannel, 12, "group", false);
+ final NotificationRecord notificationChild2 = generateNotificationRecord(
+ mTestNotificationChannel, 13, "group", false);
+ mService.addNotification(notification);
+ mService.addNotification(notificationChild);
+ mService.addNotification(notificationChild2);
+
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
+ when(mSnoozeHelper.canSnooze(3)).thenReturn(false);
+
+ NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
+ mService.new SnoozeNotificationRunnable(
+ notification.getKey(), 100, null);
+ snoozeNotificationRunnable.run();
+
+ verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong());
+ assertEquals(3, mService.getNotificationRecordCount());
+ }
+
@Test
public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);
mService.addNotification(notification);
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
- NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
- mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
// snooze twice
@@ -2816,19 +2877,17 @@ mService.new SnoozeNotificationRunnable(
}
@Test
- public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() throws Exception {
+ public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, "group", true);
mService.addNotification(notification);
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
- NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
- mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
snoozeNotificationRunnable.run();
// snooze twice
@@ -2846,6 +2905,7 @@ public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throw
when(mSnoozeHelper.getNotification(any())).thenReturn(notification);
when(mSnoozeHelper.getNotifications(
anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>());
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2855,8 +2915,8 @@ mService.new SnoozeNotificationRunnable(
.thenReturn(new ArrayList<>(Arrays.asList(notification, notification2)));
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 =
mService.new SnoozeNotificationRunnable(
- notification.getKey(), 100, null);
- snoozeNotificationRunnable.run();
+ notification2.getKey(), 100, null);
+ snoozeNotificationRunnable2.run();
// snooze twice
verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong());
@@ -2870,6 +2930,7 @@ public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
mTestNotificationChannel, 2, "group", false);
mService.addNotification(grouped);
mService.addNotification(nonGrouped);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2899,6 +2960,7 @@ public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception {
mService.addNotification(parent);
mService.addNotification(child);
mService.addNotification(child2);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2920,6 +2982,7 @@ public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exceptio
mService.addNotification(parent);
mService.addNotification(child);
mService.addNotification(child2);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2945,6 +3008,7 @@ public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exce
mTestNotificationChannel, 2, "group", false);
mService.addNotification(parent);
mService.addNotification(child);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
@@ -2972,6 +3036,7 @@ public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Excepti
final NotificationRecord child = generateNotificationRecord(
mTestNotificationChannel, 2, "group", false);
mService.addNotification(child);
+ when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true);
NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
mService.new SnoozeNotificationRunnable(
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index c2ead5f15ceb..83ba7108af7f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.notification;
+import static com.android.server.notification.SnoozeHelper.CONCURRENT_SNOOZE_LIMIT;
import static com.android.server.notification.SnoozeHelper.EXTRA_KEY;
import static junit.framework.Assert.assertEquals;
@@ -278,6 +279,22 @@ public void testSnooze() throws Exception {
UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey()));
}
+ @Test
+ public void testSnoozeLimit() {
+ for (int i = 0; i < CONCURRENT_SNOOZE_LIMIT; i++ ) {
+ NotificationRecord r = getNotificationRecord("pkg", i, i+"", UserHandle.SYSTEM);
+
+ assertTrue("cannot snooze record " + i, mSnoozeHelper.canSnooze(1));
+
+ if (i % 2 == 0) {
+ mSnoozeHelper.snooze(r, null);
+ } else {
+ mSnoozeHelper.snooze(r, 9000);
+ }
+ }
+ assertFalse(mSnoozeHelper.canSnooze(1));
+ }
+
@Test
public void testCancelByApp() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
From c0d719c6a2ae82f6edabed081e44a1dc72c785d2 Mon Sep 17 00:00:00 2001
From: Suprabh Shukla
Date: Mon, 27 Jun 2022 14:01:16 -0700
Subject: [PATCH 066/208] Stop crashing the system on hitting the alarm limit
Exempting the system as a runtime restart is not clearly
better than extreme memory and computation pressure that can result from
the originating spam.
Callers in the system should guard against any spammy requests that lead
them to create a lot of alarms.
Test: Builds, boots and existing tests should pass.
atest CtsAlarmManagerTestCases:UidCapTests
atest FrameworksMockingServicesTests:AlarmManagerServiceTest
Bug: 234441463
Change-Id: Id5e94d44ac9ab24870a8213ec7583da0f592a5ff
(cherry picked from commit 3b9f3f4a0f5a661be65e287996cae8a4481a1453)
Merged-In: Id5e94d44ac9ab24870a8213ec7583da0f592a5ff
(cherry picked from commit c010da3a4649a02afe256cbf6dad475c2278059b)
(cherry picked from commit 909251a2caf1a8734c7e3a43794399ab3d15ac76)
Merged-In: Id5e94d44ac9ab24870a8213ec7583da0f592a5ff
---
.../core/java/com/android/server/AlarmManagerService.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7cdcc01bc00d..b113a6196491 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -75,6 +75,7 @@
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.EventLog;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.LongArrayQueue;
@@ -1776,7 +1777,11 @@ void setImpl(int type, long triggerAtTime, long windowLength, long interval,
if (DEBUG_PER_UID_LIMIT && UserHandle.isCore(callingUid)) {
logAllAlarmsForUidLocked(callingUid);
}
- throw new IllegalStateException(errorMsg);
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new IllegalStateException(errorMsg);
+ } else {
+ EventLog.writeEvent(0x534e4554, "234441463", -1, errorMsg);
+ }
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, directReceiver, listenerTag, flags, true, workSource,
From edf37cddee76ca8bf45b81706714fbece6919cd8 Mon Sep 17 00:00:00 2001
From: Jeff DeCew
Date: Mon, 18 Jul 2022 13:28:21 +0000
Subject: [PATCH 067/208] Block FullScreenIntent while device is in use if
notification has a silencing GroupAlertBehavior.
Bug: 231322873
Test: atest NotificationInterruptStateProviderImplTest
Merged-In: Id82d20c9f1f2001400871b5381f52b40fbdf81c5
Change-Id: Id82d20c9f1f2001400871b5381f52b40fbdf81c5
(cherry picked from commit 09761a98b5bbbefa331c49a96b50b4e08dc3f8df)
Merged-In: Id82d20c9f1f2001400871b5381f52b40fbdf81c5
---
...otificationInterruptStateProviderImpl.java | 91 ++++++++++++--
...icationInterruptStateProviderImplTest.java | 112 ++++++++++++++++++
2 files changed, 193 insertions(+), 10 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index eeb91b548d65..8e236ea54f10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -176,9 +176,86 @@ public boolean shouldHeadsUp(NotificationEntry entry) {
*/
@Override
public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
- return entry.getSbn().getNotification().fullScreenIntent != null
- && (!shouldHeadsUp(entry)
- || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+ if (entry.getSbn().getNotification().fullScreenIntent == null) {
+ return false;
+ }
+
+ // Never show FSI when suppressed by DND
+ if (entry.shouldSuppressFullScreenIntent()) {
+ if (DEBUG) {
+ Log.d(TAG, "No FullScreenIntent: Suppressed by DND: " + entry.getKey());
+ }
+ return false;
+ }
+
+ // Never show FSI if importance is not HIGH
+ if (entry.getImportance() < NotificationManager.IMPORTANCE_HIGH) {
+ if (DEBUG) {
+ Log.d(TAG, "No FullScreenIntent: Not important enough: " + entry.getKey());
+ }
+ return false;
+ }
+
+ // If the notification has suppressive GroupAlertBehavior, block FSI and warn.
+ StatusBarNotification sbn = entry.getSbn();
+ if (sbn.isGroup() && sbn.getNotification().suppressAlertingDueToGrouping()) {
+ // b/231322873: Detect and report an event when a notification has both an FSI and a
+ // suppressive groupAlertBehavior, and now correctly block the FSI from firing.
+ final int uid = entry.getSbn().getUid();
+ android.util.EventLog.writeEvent(0x534e4554, "231322873", uid, "groupAlertBehavior");
+ if (DEBUG) {
+ Log.w(TAG, "No FullScreenIntent: WARNING: GroupAlertBehavior will prevent HUN: "
+ + entry.getKey());
+ }
+ return false;
+ }
+
+ // If the screen is off, then launch the FullScreenIntent
+ if (!mPowerManager.isInteractive()) {
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Device is not interactive: " + entry.getKey());
+ }
+ return true;
+ }
+
+ // If the device is currently dreaming, then launch the FullScreenIntent
+ if (isDreaming()) {
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Device is dreaming: " + entry.getKey());
+ }
+ return true;
+ }
+
+ // If the keyguard is showing, then launch the FullScreenIntent
+ if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Keyguard is showing: " + entry.getKey());
+ }
+ return true;
+ }
+
+ // If the notification should HUN, then we don't need FSI
+ if (shouldHeadsUp(entry)) {
+ if (DEBUG) {
+ Log.d(TAG, "No FullScreenIntent: Expected to HUN: " + entry.getKey());
+ }
+ return false;
+ }
+
+ // If the notification won't HUN for some other reason (DND/snooze/etc), launch FSI.
+ if (DEBUG) {
+ Log.d(TAG, "FullScreenIntent: Expected not to HUN: " + entry.getKey());
+ }
+ return true;
+ }
+
+ private boolean isDreaming() {
+ try {
+ return mDreamManager.isDreaming();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query dream manager.", e);
+ return false;
+ }
}
private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
@@ -229,13 +306,7 @@ private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
return false;
}
- boolean isDreaming = false;
- try {
- isDreaming = mDreamManager.isDreaming();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to query dream manager.", e);
- }
- boolean inUse = mPowerManager.isScreenOn() && !isDreaming;
+ boolean inUse = mPowerManager.isScreenOn() && !isDreaming();
if (!inUse) {
if (DEBUG_HEADS_UP) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index e254cd2c82a7..f4455ddb25bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -24,6 +24,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.google.common.truth.Truth.assertThat;
@@ -84,6 +85,8 @@ public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
BatteryController mBatteryController;
@Mock
Handler mMockHandler;
+ @Mock
+ PendingIntent mPendingIntent;
private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@@ -399,6 +402,97 @@ public void testShouldNotHeadsUp_justLaunchedFullscreen() {
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
+ @Test
+ public void testShouldNotFullScreen_notPendingIntent() throws RemoteException {
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldNotFullScreen_notHighImportance() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_DEFAULT, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldNotFullScreen_isGroupAlertSilenced() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ true);
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ when(mDreamManager.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldFullScreen_notInteractive() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(false);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
+ @Test
+ public void testShouldFullScreen_isDreaming() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
+ @Test
+ public void testShouldFullScreen_onKeyguard() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(KEYGUARD);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
+ @Test
+ public void testShouldNotFullScreen_willHun() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isFalse();
+ }
+
+ @Test
+ public void testShouldFullScreen_packageSnoozed() throws RemoteException {
+ NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silenced */ false);
+ when(mPowerManager.isInteractive()).thenReturn(true);
+ when(mPowerManager.isScreenOn()).thenReturn(true);
+ when(mDreamManager.isDreaming()).thenReturn(false);
+ when(mStatusBarStateController.getState()).thenReturn(SHADE);
+ when(mHeadsUpManager.isSnoozed("a")).thenReturn(true);
+
+ assertThat(mNotifInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry))
+ .isTrue();
+ }
+
/**
* Bubbles can happen.
*/
@@ -502,6 +596,10 @@ private NotificationEntry createNotification(int importance) {
.setContentText("content text")
.build();
+ return createNotification(importance, n);
+ }
+
+ private NotificationEntry createNotification(int importance, Notification n) {
return new NotificationEntryBuilder()
.setPkg("a")
.setOpPkg("a")
@@ -511,6 +609,20 @@ private NotificationEntry createNotification(int importance) {
.build();
}
+ private NotificationEntry createFsiNotification(int importance, boolean silent) {
+ Notification n = new Notification.Builder(getContext(), "a")
+ .setContentTitle("title")
+ .setContentText("content text")
+ .setFullScreenIntent(mPendingIntent, true)
+ .setGroup("fsi")
+ .setGroupAlertBehavior(silent
+ ? Notification.GROUP_ALERT_SUMMARY
+ : Notification.GROUP_ALERT_ALL)
+ .build();
+
+ return createNotification(importance, n);
+ }
+
private final NotificationInterruptSuppressor
mSuppressAwakeHeadsUp =
new NotificationInterruptSuppressor() {
From dda51b9212dda11d5bab90c2a5ed7f91d7af4eee Mon Sep 17 00:00:00 2001
From: Linus Tufvesson
Date: Fri, 5 Aug 2022 15:14:16 +0200
Subject: [PATCH 068/208] DO NOT MERGE - Exclude TYPE_PRIVATE_PRESENTATION app
visiblity
These windows can only be placed on private virtual displays, and as
such they should not be considered when deciding if an application has
any visible windows or not.
Bug:205130886
Test:Manually verified that sample from 205130886 no longer allows
background activity launches
Test: atest CtsActivityManagerBackgroundActivityTestCases
Change-Id: I76208722bbb7a407ba1f2dc4305a28226166414d
Merged-In: I76208722bbb7a407ba1f2dc4305a28226166414d
(cherry picked from commit 778191bdf21661b41030f9308e095c0445dec33c)
Merged-In: I76208722bbb7a407ba1f2dc4305a28226166414d
---
.../android/server/wm/RootWindowContainer.java | 5 +++--
.../com/android/server/wm/WindowState.java | 18 +++++++++++-------
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f173c0b1caf9..e240af134435 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -571,8 +571,9 @@ private void getWindowsByName(ArrayList output, String name, int ob
/**
* Returns {@code true} if the callingUid has any non-toast window currently visible to the
* user. Also ignores {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_STARTING},
- * since those windows don't belong to apps.
- * @see WindowState#isNonToastOrStarting()
+ * and{@link android.view.WindowManager.LayoutParams#TYPE_PRIVATE_PRESENTATION}, as they
+ * should not count towards the apps visibility
+ * @see WindowState#isNonToastOrStartingOrPrivatePresentation()
*/
boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
final PooledPredicate p = PooledLambda.obtainPredicate(
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index faa483a48ea4..522b8d8fcce8 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5812,20 +5812,24 @@ void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
}
/**
- * Returns {@code true} if this window is not {@link WindowManager.LayoutParams#TYPE_TOAST}
- * or {@link WindowManager.LayoutParams#TYPE_APPLICATION_STARTING},
- * since this window doesn't belong to apps.
+ * Returns {@code true} if this window is not {@link WindowManager.LayoutParams#TYPE_TOAST},
+ * {@link WindowManager.LayoutParams#TYPE_APPLICATION_STARTING} or
+ * {@link WindowManager.LayoutParams#TYPE_PRIVATE_PRESENTATION},
+ * since those windows should not count towards the apps visibility.
*/
- boolean isNonToastOrStarting() {
- return mAttrs.type != TYPE_TOAST && mAttrs.type != TYPE_APPLICATION_STARTING;
+ boolean isNonToastOrStartingOrPrivatePresentation() {
+ return mAttrs.type != TYPE_TOAST && mAttrs.type != TYPE_APPLICATION_STARTING
+ && mAttrs.type != TYPE_PRIVATE_PRESENTATION;
}
boolean isNonToastWindowVisibleForUid(int callingUid) {
- return getOwningUid() == callingUid && isNonToastOrStarting() && isVisibleNow();
+ return getOwningUid() == callingUid && isNonToastOrStartingOrPrivatePresentation()
+ && isVisibleNow();
}
boolean isNonToastWindowVisibleForPid(int pid) {
- return mSession.mPid == pid && isNonToastOrStarting() && isVisibleNow();
+ return mSession.mPid == pid && isNonToastOrStartingOrPrivatePresentation()
+ && isVisibleNow();
}
void setViewVisibility(int viewVisibility) {
From 9d9e13c487a18cdd75edb8f594310aed5e0fa78c Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Wed, 16 Jun 2021 14:00:23 -0400
Subject: [PATCH 069/208] Store DND rule owners
Test: uiservicestest, cts
Bug: 189332346
Bug: 235823407
Change-Id: Ie546c15c25fcbd193b67cb997220f075691e9bab
Merged-In: Ie546c15c25fcbd193b67cb997220f075691e9bab
(cherry picked from commit 422cffbefa80c3b248458ef8ffe58d5fcf90ea3b)
Merged-In: Ie546c15c25fcbd193b67cb997220f075691e9bab
---
core/java/android/app/AutomaticZenRule.java | 21 ++++++-
.../android/app/INotificationManager.aidl | 2 +-
.../java/android/app/NotificationManager.java | 8 ++-
.../service/notification/ZenModeConfig.java | 15 +++--
.../NotificationManagerService.java | 5 +-
.../server/notification/ZenModeHelper.java | 19 ++++---
.../NotificationManagerServiceTest.java | 6 +-
.../notification/ZenModeConfigTest.java | 55 ++++++++++++++++++-
.../notification/ZenModeHelperTest.java | 2 +-
9 files changed, 106 insertions(+), 27 deletions(-)
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 7180c01143a5..a6cd6d511caf 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -45,6 +45,7 @@ public final class AutomaticZenRule implements Parcelable {
private long creationTime;
private ZenPolicy mZenPolicy;
private boolean mModified = false;
+ private String mPkg;
/**
* Creates an automatic zen rule.
@@ -123,6 +124,7 @@ public AutomaticZenRule(Parcel source) {
creationTime = source.readLong();
mZenPolicy = source.readParcelable(null);
mModified = source.readInt() == ENABLED;
+ mPkg = source.readString();
}
/**
@@ -244,6 +246,20 @@ public void setConfigurationActivity(@Nullable ComponentName componentName) {
this.configurationActivity = componentName;
}
+ /**
+ * @hide
+ */
+ public void setPackageName(String pkgName) {
+ mPkg = pkgName;
+ }
+
+ /**
+ * @hide
+ */
+ public String getPackageName() {
+ return mPkg;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -265,6 +281,7 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(creationTime);
dest.writeParcelable(mZenPolicy, 0);
dest.writeInt(mModified ? ENABLED : DISABLED);
+ dest.writeString(mPkg);
}
@Override
@@ -273,6 +290,7 @@ public String toString() {
.append("enabled=").append(enabled)
.append(",name=").append(name)
.append(",interruptionFilter=").append(interruptionFilter)
+ .append(",pkg=").append(mPkg)
.append(",conditionId=").append(conditionId)
.append(",owner=").append(owner)
.append(",configActivity=").append(configurationActivity)
@@ -294,13 +312,14 @@ public boolean equals(Object o) {
&& Objects.equals(other.owner, owner)
&& Objects.equals(other.mZenPolicy, mZenPolicy)
&& Objects.equals(other.configurationActivity, configurationActivity)
+ && Objects.equals(other.mPkg, mPkg)
&& other.creationTime == creationTime;
}
@Override
public int hashCode() {
return Objects.hash(enabled, name, interruptionFilter, conditionId, owner,
- configurationActivity, mZenPolicy, mModified, creationTime);
+ configurationActivity, mZenPolicy, mModified, creationTime, mPkg);
}
public static final @android.annotation.NonNull Parcelable.Creator CREATOR
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index a5f987adb1a7..863fe4d5f6b1 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -203,7 +203,7 @@ interface INotificationManager
void setNotificationPolicyAccessGrantedForUser(String pkg, int userId, boolean granted);
AutomaticZenRule getAutomaticZenRule(String id);
List getZenRules();
- String addAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+ String addAutomaticZenRule(in AutomaticZenRule automaticZenRule, String pkg);
boolean updateAutomaticZenRule(String id, in AutomaticZenRule automaticZenRule);
boolean removeAutomaticZenRule(String id);
boolean removeAutomaticZenRules(String packageName);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index eef9c022fda8..553cc91fdd5f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1072,10 +1072,12 @@ public Map getAutomaticZenRules() {
List rules = service.getZenRules();
Map ruleMap = new HashMap<>();
for (ZenModeConfig.ZenRule rule : rules) {
- ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+ AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component,
rule.configurationActivity, rule.conditionId, rule.zenPolicy,
zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
- rule.creationTime));
+ rule.creationTime);
+ azr.setPackageName(rule.pkg);
+ ruleMap.put(rule.id, azr);
}
return ruleMap;
} catch (RemoteException e) {
@@ -1116,7 +1118,7 @@ public AutomaticZenRule getAutomaticZenRule(String id) {
public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
INotificationManager service = getService();
try {
- return service.addAutomaticZenRule(automaticZenRule);
+ return service.addAutomaticZenRule(automaticZenRule, mContext.getPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 0827fef60252..9c6e0ef4cec3 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -46,6 +46,7 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -159,6 +160,7 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_ENABLED = "enabled";
private static final String RULE_ATT_SNOOZING = "snoozing";
private static final String RULE_ATT_NAME = "name";
+ private static final String RULE_ATT_PKG = "pkg";
private static final String RULE_ATT_COMPONENT = "component";
private static final String RULE_ATT_CONFIG_ACTIVITY = "configActivity";
private static final String RULE_ATT_ZEN = "zen";
@@ -669,11 +671,11 @@ public static ZenRule readRuleXml(XmlPullParser parser) {
rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
rt.configurationActivity = safeComponentName(parser, RULE_ATT_CONFIG_ACTIVITY);
- rt.pkg = (rt.component != null)
- ? rt.component.getPackageName()
- : (rt.configurationActivity != null)
- ? rt.configurationActivity.getPackageName()
- : null;
+ rt.pkg = XmlUtils.readStringAttribute(parser, RULE_ATT_PKG);
+ if (rt.pkg == null) {
+ // backfill from component, if present. configActivity is not safe to backfill from
+ rt.pkg = rt.component != null ? rt.component.getPackageName() : null;
+ }
rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0);
rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER);
rt.condition = readConditionXml(parser);
@@ -695,6 +697,9 @@ public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOExcept
out.attribute(null, RULE_ATT_NAME, rule.name);
}
out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode));
+ if (rule.pkg != null) {
+ out.attribute(null, RULE_ATT_PKG, rule.pkg);
+ }
if (rule.component != null) {
out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString());
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index dd8f3e11b575..77c440e95c08 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4506,7 +4506,7 @@ public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
}
@Override
- public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg) {
Objects.requireNonNull(automaticZenRule, "automaticZenRule is null");
Objects.requireNonNull(automaticZenRule.getName(), "Name is null");
if (automaticZenRule.getOwner() == null
@@ -4515,6 +4515,7 @@ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
"Rule must have a conditionproviderservice and/or configuration activity");
}
Objects.requireNonNull(automaticZenRule.getConditionId(), "ConditionId is null");
+ checkCallerIsSameApp(pkg);
if (automaticZenRule.getZenPolicy() != null
&& automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
throw new IllegalArgumentException("ZenPolicy is only applicable to "
@@ -4522,7 +4523,7 @@ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
}
enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
- return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
+ return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
"addAutomaticZenRule");
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 49a016cb45b0..fc536a985d34 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -303,7 +303,8 @@ public AutomaticZenRule getAutomaticZenRule(String id) {
return null;
}
- public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
+ public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
+ String reason) {
if (!isSystemRule(automaticZenRule)) {
PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
if (component == null) {
@@ -336,7 +337,7 @@ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reas
}
newConfig = mConfig.copy();
ZenRule rule = new ZenRule();
- populateZenRule(automaticZenRule, rule, true);
+ populateZenRule(pkg, automaticZenRule, rule, true);
newConfig.automaticRules.put(rule.id, rule);
if (setConfigLocked(newConfig, reason, rule.component, true)) {
return rule.id;
@@ -372,7 +373,7 @@ public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZ
? AUTOMATIC_RULE_STATUS_ENABLED : AUTOMATIC_RULE_STATUS_DISABLED);
}
- populateZenRule(automaticZenRule, rule, false);
+ populateZenRule(rule.pkg, automaticZenRule, rule, false);
return setConfigLocked(newConfig, reason, rule.component, true);
}
}
@@ -568,15 +569,14 @@ private ActivityInfo getActivityInfo(ComponentName configActivity) {
return null;
}
- private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) {
+ private void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule,
+ boolean isNew) {
if (isNew) {
rule.id = ZenModeConfig.newRuleId();
rule.creationTime = System.currentTimeMillis();
rule.component = automaticZenRule.getOwner();
rule.configurationActivity = automaticZenRule.getConfigurationActivity();
- rule.pkg = (rule.component != null)
- ? rule.component.getPackageName()
- : rule.configurationActivity.getPackageName();
+ rule.pkg = pkg;
}
if (rule.enabled != automaticZenRule.isEnabled()) {
@@ -593,10 +593,13 @@ private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, bo
}
protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
- return new AutomaticZenRule(rule.name, rule.component, rule.configurationActivity,
+ AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component,
+ rule.configurationActivity,
rule.conditionId, rule.zenPolicy,
NotificationManager.zenModeToInterruptionFilter(rule.zenMode),
rule.enabled, rule.creationTime);
+ azr.setPackageName(rule.pkg);
+ return azr;
}
public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) {
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 88d7680d9236..2239769a3525 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5921,7 +5921,7 @@ public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Except
zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
try {
- mBinderService.addAutomaticZenRule(rule);
+ mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
fail("Zen policy only applies to priority only mode");
} catch (IllegalArgumentException e) {
// yay
@@ -5929,11 +5929,11 @@ public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Except
rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
- mBinderService.addAutomaticZenRule(rule);
+ mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
- mBinderService.addAutomaticZenRule(rule);
+ mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 013a99433041..684d8cfed5b6 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -188,7 +188,7 @@ public void testRuleXml() throws Exception {
ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
rule.configurationActivity = new ComponentName("a", "a");
- rule.component = new ComponentName("a", "b");
+ rule.component = new ComponentName("b", "b");
rule.conditionId = new Uri.Builder().scheme("hello").build();
rule.condition = new Condition(rule.conditionId, "", Condition.STATE_TRUE);
rule.enabled = true;
@@ -198,6 +198,7 @@ public void testRuleXml() throws Exception {
rule.modified = true;
rule.name = "name";
rule.snoozing = true;
+ rule.pkg = "b";
XmlSerializer out = new FastXmlSerializer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -213,8 +214,7 @@ public void testRuleXml() throws Exception {
new ByteArrayInputStream(baos.toByteArray())), null);
parser.nextTag();
ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
- // read from backing component
- assertEquals("a", fromXml.pkg);
+ assertEquals("b", fromXml.pkg);
// always resets on reboot
assertFalse(fromXml.snoozing);
//should all match original
@@ -230,6 +230,55 @@ public void testRuleXml() throws Exception {
assertEquals(rule.zenMode, fromXml.zenMode);
}
+ @Test
+ public void testRuleXml_pkg_component() throws Exception {
+ String tag = "tag";
+
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.configurationActivity = new ComponentName("a", "a");
+ rule.component = new ComponentName("b", "b");
+
+ XmlSerializer out = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ out.setOutput(new BufferedOutputStream(baos), "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, tag);
+ ZenModeConfig.writeRuleXml(rule, out);
+ out.endTag(null, tag);
+ out.endDocument();
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
+ assertEquals("b", fromXml.pkg);
+ }
+
+ @Test
+ public void testRuleXml_pkg_configActivity() throws Exception {
+ String tag = "tag";
+
+ ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+ rule.configurationActivity = new ComponentName("a", "a");
+
+ XmlSerializer out = new FastXmlSerializer();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ out.setOutput(new BufferedOutputStream(baos), "utf-8");
+ out.startDocument(null, true);
+ out.startTag(null, tag);
+ ZenModeConfig.writeRuleXml(rule, out);
+ out.endTag(null, tag);
+ out.endDocument();
+
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(
+ new ByteArrayInputStream(baos.toByteArray())), null);
+ parser.nextTag();
+ ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser);
+ assertNull(fromXml.pkg);
+ }
+
private ZenModeConfig getMutedRingerConfig() {
ZenModeConfig config = new ZenModeConfig();
// Allow alarms, media
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index c98745e9041d..a928d4dc592f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1562,7 +1562,7 @@ public void testAddAutomaticZenRule() {
new ComponentName("android", "ScheduleConditionProvider"),
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test");
+ String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test");
assertTrue(id != null);
ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id);
From e3e0e9af11180d0e43bed8fe7701aff13613fd2a Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Tue, 22 Jun 2021 13:30:37 -0400
Subject: [PATCH 070/208] Fix NPE when deleting old zen rules
Test: manually revoke access for a DND app that has rules
created before and after b/189332346
Bug: 191773100
Bug: 189332346
Bug: 235823407
Change-Id: I069fcc124af24227fa50b61d4fc55d6dadc7a20b
Merged-In: I069fcc124af24227fa50b61d4fc55d6dadc7a20b
(cherry picked from commit b4fe101e5e609f3f24ec471a35a7e0e96a416834)
(cherry picked from commit 66896a01fa817c3546aacae23d326c37344984ec)
Merged-In: I069fcc124af24227fa50b61d4fc55d6dadc7a20b
---
.../com/android/server/notification/ZenModeHelper.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index fc536a985d34..a5d846203207 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -405,7 +405,14 @@ public boolean removeAutomaticZenRules(String packageName, String reason) {
newConfig = mConfig.copy();
for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) {
+ String pkg = rule.pkg != null
+ ? rule.pkg
+ : (rule.component != null)
+ ? rule.component.getPackageName()
+ : (rule.configurationActivity != null)
+ ? rule.configurationActivity.getPackageName()
+ : null;
+ if (Objects.equals(pkg, packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
}
}
From 973784782fc63a82a53eea7dff4229a3c9b089f4 Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Tue, 28 Jun 2022 15:43:33 -0400
Subject: [PATCH 071/208] Enforce zen rule limit on a package level.
This means that a single package with multiple different condition providers or configuration activities will correctly have all of their zen rules associated with the same package rather than each owner/activity having their rules counted separately.
Bug: 235823407
Test: ZenModeHelperTest
Change-Id: I35daf9a24f546ae25a78a2d841be39072cdc5641
Merged-In: I35daf9a24f546ae25a78a2d841be39072cdc5641
(cherry picked from commit f4e69394eee569ac3ec5748094b9ce88a91c278c)
(cherry picked from commit 468dd54e8b59ca494e5e3258a914447e5168ceaf)
Merged-In: I35daf9a24f546ae25a78a2d841be39072cdc5641
---
.../server/notification/ZenModeHelper.java | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a5d846203207..1c55762f132d 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -321,7 +321,8 @@ public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner())
+ getCurrentInstanceCount(automaticZenRule.getConfigurationActivity())
+ 1;
- if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE
+ int newPackageRuleCount = getPackageRuleCount(pkg) + 1;
+ if (newPackageRuleCount > RULE_LIMIT_PER_PACKAGE
|| (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) {
throw new IllegalArgumentException("Rule instance limit exceeded");
}
@@ -495,6 +496,23 @@ public int getCurrentInstanceCount(ComponentName cn) {
return count;
}
+ // Equivalent method to getCurrentInstanceCount, but for all rules associated with a specific
+ // package rather than a condition provider service or activity.
+ private int getPackageRuleCount(String pkg) {
+ if (pkg == null) {
+ return 0;
+ }
+ int count = 0;
+ synchronized (mConfig) {
+ for (ZenRule rule : mConfig.automaticRules.values()) {
+ if (pkg.equals(rule.pkg)) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
public boolean canManageAutomaticZenRule(ZenRule rule) {
final int callingUid = Binder.getCallingUid();
if (callingUid == 0 || callingUid == Process.SYSTEM_UID) {
From c3a8fce195257589ab092fbb3835644318c65a2e Mon Sep 17 00:00:00 2001
From: Aseem Kumar
Date: Mon, 21 Mar 2022 20:35:20 -0700
Subject: [PATCH 072/208] DO NOT MERGE Move accountname and typeName length
check from Account.java to AccountManagerService.
Bug: 169762606
Test: atest AccountManagerServiceTest
Change-Id: I80fabf3a64c55837db98ff316e7e5420129c001b
(cherry picked from commit 0adcadb0b28310bac568def4da2cbaf16843bcea)
Merged-In: I80fabf3a64c55837db98ff316e7e5420129c001b
(cherry picked from commit aa58f99079ed8adac51b6b21faae24cb1c86262b)
Merged-In: I80fabf3a64c55837db98ff316e7e5420129c001b
---
.../accounts/AccountManagerService.java | 12 ++++++++++
.../accounts/AccountManagerServiceTest.java | 22 +++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 90dc03642a86..e24030188c62 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1806,6 +1806,14 @@ private boolean addAccountInternal(UserAccounts accounts, Account account, Strin
if (account == null) {
return false;
}
+ if (account.name != null && account.name.length() > 200) {
+ Log.w(TAG, "Account cannot be added - Name longer than 200 chars");
+ return false;
+ }
+ if (account.type != null && account.type.length() > 200) {
+ Log.w(TAG, "Account cannot be added - Name longer than 200 chars");
+ return false;
+ }
if (!isLocalUnlockedUser(accounts.userId)) {
Log.w(TAG, "Account " + account.toSafeString() + " cannot be added - user "
+ accounts.userId + " is locked. callingUid=" + callingUid);
@@ -1999,6 +2007,10 @@ public void renameAccount(
+ ", pid " + Binder.getCallingPid());
}
if (accountToRename == null) throw new IllegalArgumentException("account is null");
+ if (newName != null && newName.length() > 200) {
+ Log.e(TAG, "renameAccount failed - account name longer than 200");
+ throw new IllegalArgumentException("account name longer than 200");
+ }
int userId = UserHandle.getCallingUserId();
if (!isAccountManagedByCaller(accountToRename.type, callingUid, userId)) {
String msg = String.format(
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 39a3aae767ea..ac305a93bfb8 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -36,6 +36,7 @@
import android.accounts.IAccountManagerResponse;
import android.app.AppOpsManager;
import android.app.INotificationManager;
+import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
@@ -132,6 +133,8 @@ public class AccountManagerServiceTest extends AndroidTestCase {
protected void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ PropertyInvalidatedCache.disableForTestMode();
+
when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
.thenReturn(PackageManager.SIGNATURE_MATCH);
final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
@@ -241,6 +244,25 @@ public void testCheckAddAccount() throws Exception {
assertEquals(a31, accounts[1]);
}
+ @SmallTest
+ public void testCheckAddAccountLongName() throws Exception {
+ unlockSystemUser();
+ String longString = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ + "aaaaa";
+ Account a11 = new Account(longString, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+
+ mAms.addAccountExplicitly(a11, /* password= */ "p11", /* extras= */ null);
+
+ String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+ when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+ Account[] accounts = mAms.getAccountsAsUser(null,
+ UserHandle.getCallingUserId(), mContext.getOpPackageName());
+ assertEquals(0, accounts.length);
+ }
+
+
@SmallTest
public void testPasswords() throws Exception {
unlockSystemUser();
From 902d3bdfe0af42fa2376009d5c7e91cad48e739a Mon Sep 17 00:00:00 2001
From: Thomas Stuart
Date: Thu, 23 Jun 2022 14:27:43 -0700
Subject: [PATCH 073/208] switch TelecomManager List getters to
ParceledListSlice
It was shown that given a large phoneAccountHandles that are
over 1 mb, a TransactionTooLarge exception can be silently thrown
causing an empty list to be returned.
In order to prevent this behavior, all Lists that return a
PhoneAccountHandle or PhoneAccount have been switched to
ParceledListSlice.
bug: 236263294
Test: atest android.telecom.cts.PhoneAccountRegistrarTest
#testRegisterPhoneAccountHandleWithFieldOverLimit
Change-Id: I025245b2a6f8cfaca86f268851a9d8f0817e07dd
Merged-In: I025245b2a6f8cfaca86f268851a9d8f0817e07dd
(cherry picked from commit f5ab5186dac6dd710693716c13413f30791be0e9)
Merged-In: I025245b2a6f8cfaca86f268851a9d8f0817e07dd
---
telecomm/java/android/telecom/TelecomManager.java | 13 +++++++------
.../android/internal/telecom/ITelecomService.aidl | 13 +++++++------
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index c160023ca944..19a88001428d 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1153,7 +1153,7 @@ public List getPhoneAccountsSupportingScheme(String uriSchem
try {
if (isServiceConnected()) {
return getTelecomService().getPhoneAccountsSupportingScheme(uriScheme,
- mContext.getOpPackageName());
+ mContext.getOpPackageName()).getList();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsSupportingScheme", e);
@@ -1196,7 +1196,7 @@ public List getSelfManagedPhoneAccounts() {
try {
if (isServiceConnected()) {
return getTelecomService().getSelfManagedPhoneAccounts(mContext.getOpPackageName(),
- mContext.getAttributionTag());
+ mContext.getAttributionTag()).getList();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSelfManagedPhoneAccounts()", e);
@@ -1222,7 +1222,7 @@ public List getSelfManagedPhoneAccounts() {
try {
if (isServiceConnected()) {
return getTelecomService().getCallCapablePhoneAccounts(includeDisabledAccounts,
- mContext.getOpPackageName(), mContext.getAttributionTag());
+ mContext.getOpPackageName(), mContext.getAttributionTag()).getList();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
@@ -1242,7 +1242,8 @@ public List getSelfManagedPhoneAccounts() {
public List getPhoneAccountsForPackage() {
try {
if (isServiceConnected()) {
- return getTelecomService().getPhoneAccountsForPackage(mContext.getPackageName());
+ return getTelecomService()
+ .getPhoneAccountsForPackage(mContext.getPackageName()).getList();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsForPackage", e);
@@ -1296,7 +1297,7 @@ public int getAllPhoneAccountsCount() {
public List getAllPhoneAccounts() {
try {
if (isServiceConnected()) {
- return getTelecomService().getAllPhoneAccounts();
+ return getTelecomService().getAllPhoneAccounts().getList();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getAllPhoneAccounts", e);
@@ -1314,7 +1315,7 @@ public List getAllPhoneAccounts() {
public List getAllPhoneAccountHandles() {
try {
if (isServiceConnected()) {
- return getTelecomService().getAllPhoneAccountHandles();
+ return getTelecomService().getAllPhoneAccountHandles().getList();
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getAllPhoneAccountHandles", e);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index dee5a98e33e9..d27093ad0133 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -23,6 +23,7 @@ import android.telecom.PhoneAccountHandle;
import android.net.Uri;
import android.os.Bundle;
import android.telecom.PhoneAccount;
+import android.content.pm.ParceledListSlice;
/**
* Interface used to interact with Telecom. Mostly this is used by TelephonyManager for passing
@@ -56,25 +57,25 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#getCallCapablePhoneAccounts
*/
- List getCallCapablePhoneAccounts(
+ ParceledListSlice getCallCapablePhoneAccounts(
boolean includeDisabledAccounts, String callingPackage, String callingFeatureId);
/**
* @see TelecomServiceImpl#getSelfManagedPhoneAccounts
*/
- List getSelfManagedPhoneAccounts(String callingPackage,
+ ParceledListSlice getSelfManagedPhoneAccounts(String callingPackage,
String callingFeatureId);
/**
* @see TelecomManager#getPhoneAccountsSupportingScheme
*/
- List getPhoneAccountsSupportingScheme(in String uriScheme,
+ ParceledListSlice getPhoneAccountsSupportingScheme(in String uriScheme,
String callingPackage);
/**
* @see TelecomManager#getPhoneAccountsForPackage
*/
- List getPhoneAccountsForPackage(in String packageName);
+ ParceledListSlice getPhoneAccountsForPackage(in String packageName);
/**
* @see TelecomManager#getPhoneAccount
@@ -89,12 +90,12 @@ interface ITelecomService {
/**
* @see TelecomManager#getAllPhoneAccounts
*/
- List getAllPhoneAccounts();
+ ParceledListSlice getAllPhoneAccounts();
/**
* @see TelecomManager#getAllPhoneAccountHandles
*/
- List getAllPhoneAccountHandles();
+ ParceledListSlice getAllPhoneAccountHandles();
/**
* @see TelecomServiceImpl#getSimCallManager
From ce6b5f925e1df482f31c906214436a49a5ac6b99 Mon Sep 17 00:00:00 2001
From: Louis Chang
Date: Tue, 2 Aug 2022 03:33:39 +0000
Subject: [PATCH 074/208] [RESTRICT AUTOMERGE] Do not send new Intent to
non-exported activity when navigateUpTo
The new Intent was delivered to a non-exported activity while
#navigateUpTo was called from an Activity of a different uid.
Bug: 238605611
Test: atest StartActivityTests
Change-Id: I854dd825bfd9a2c08851980d480d1f3a177af6cf
Merged-In: I854dd825bfd9a2c08851980d480d1f3a177af6cf
(cherry picked from commit 834812c423f10deb95953d41a7007d4cba78f1ec)
Merged-In: I854dd825bfd9a2c08851980d480d1f3a177af6cf
---
.../com/android/server/wm/ActivityStack.java | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6d452c39eccc..071e9a56e5f5 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2404,7 +2404,23 @@ boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants des
parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
(destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- parent.deliverNewIntentLocked(callingUid, destIntent, destGrants, srec.packageName);
+ boolean abort;
+ try {
+ abort = !mStackSupervisor.checkStartAnyActivityPermission(destIntent,
+ parent.info, null /* resultWho */, -1 /* requestCode */, srec.getPid(),
+ callingUid, srec.info.packageName, null /* callingFeatureId */,
+ false /* ignoreTargetSecurity */, false /* launchingInTask */, srec.app,
+ null /* resultRecord */, null /* resultRootTask */);
+ } catch (SecurityException e) {
+ abort = true;
+ }
+ if (abort) {
+ android.util.EventLog.writeEvent(0x534e4554, "238605611", callingUid, "");
+ foundParentInTask = false;
+ } else {
+ parent.deliverNewIntentLocked(callingUid, destIntent, destGrants,
+ srec.packageName);
+ }
} else {
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
From 50ec233b7bc8b8b8bfed65d6126dd59b167ed68e Mon Sep 17 00:00:00 2001
From: Daniel Norman
Date: Fri, 12 Aug 2022 11:40:41 -0700
Subject: [PATCH 075/208] Do not send AccessibilityEvent if notification is for
different user.
Bug: 237540408
Test: BuzzBeepBlinkTest#testA11yCrossUserEventNotSent
Change-Id: I62a875e26e214847ec72ce3c41b4f2fa8e597e07
(cherry picked from commit a367c0a16a9070ed6bee3028ac5bbc967773ee8f)
Merged-In: I62a875e26e214847ec72ce3c41b4f2fa8e597e07
---
.../notification/NotificationManagerService.java | 3 ++-
.../server/notification/BuzzBeepBlinkTest.java | 15 +++++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 77c440e95c08..60d7ec51ca09 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7075,7 +7075,8 @@ int buzzBeepBlinkLocked(NotificationRecord record) {
&& (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
- && !suppressedByDnd) {
+ && !suppressedByDnd
+ && isNotificationForCurrentUser(record)) {
sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index a21bfda58529..9bf8758c6a8b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -1281,6 +1281,21 @@ public void testA11yQuietUpdate() throws Exception {
verify(mAccessibilityService, times(1)).sendAccessibilityEvent(any(), anyInt());
}
+ @Test
+ public void testA11yCrossUserEventNotSent() throws Exception {
+ final Notification n = new Builder(getContext(), "test")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon).build();
+ int userId = mUser.getIdentifier() + 1;
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
+ mPid, n, UserHandle.of(userId), null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn,
+ new NotificationChannel("test", "test", IMPORTANCE_HIGH));
+
+ mService.buzzBeepBlinkLocked(r);
+
+ verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt());
+ }
+
@Test
public void testLightsScreenOn() {
mService.mScreenOn = true;
From 8d96665f69de3631562cf642cfc23ee4e995c072 Mon Sep 17 00:00:00 2001
From: Ganesh Olekar
Date: Thu, 30 Jun 2022 00:20:15 +0000
Subject: [PATCH 076/208] DO NOT MERGE Fix auto-grant of AR runtime permission
if device is upgrading from pre-Q
Test: Manually install app apks targeting Q and verifying that AR permission is not auto-granted
Test: atest ActivityRecognitionPermissionTest
Bug: 210065877
Change-Id: I7004055c9573d17f31255c2b1adee1e0aeeb238f
(cherry picked from commit f11f26c0121152ffa5c8493ebbedb9fd369ec6c4)
Merged-In: I7004055c9573d17f31255c2b1adee1e0aeeb238f
---
.../content/pm/PackageManagerInternal.java | 6 ++++
.../server/pm/PackageManagerService.java | 5 +++
.../permission/PermissionManagerService.java | 34 +++++++++++--------
3 files changed, 31 insertions(+), 14 deletions(-)
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index b241bd16d3ee..83801ff0534c 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -998,4 +998,10 @@ public abstract void setIntegrityVerificationResult(int verificationId,
* Returns {@code true} if the package is suspending any packages for the user.
*/
public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
+
+ /**
+ * Get installed SDK version of the package
+ * @param pkg package for which to retrieve the installed sdk version
+ */
+ public abstract int getInstalledSdkVersion(AndroidPackage pkg);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 71e665122167..4c5e966f54c0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -25295,6 +25295,11 @@ public void unsuspendForSuspendingPackage(final String packageName, int affected
public boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
return PackageManagerService.this.isSuspendingAnyPackages(suspendingPackage, userId);
}
+
+ @Override
+ public int getInstalledSdkVersion(AndroidPackage pkg) {
+ return PackageManagerService.this.getSettingsVersionForPackage(pkg).sdkVersion;
+ }
}
@GuardedBy("mLock")
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 8d2363b6e831..663f6ebcd73a 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2755,7 +2755,7 @@ private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace
// uids the original and new state are the same object
if (!origPermissions.hasRequestedPermission(permName)
&& (pkg.getImplicitPermissions().contains(permName)
- || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
+ || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
if (pkg.getImplicitPermissions().contains(permName)) {
// If permName is an implicit permission, try to auto-grant
newImplicitPermissions.add(permName);
@@ -2771,21 +2771,27 @@ private void restorePermissionState(@NonNull AndroidPackage pkg, boolean replace
// or has updated its target SDK and AR is no longer implicit to it.
// This is a compatibility workaround for apps when AR permission was
// split in Q.
- final List permissionList =
- getSplitPermissions();
- int numSplitPerms = permissionList.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
- String splitPermName = sp.getSplitPermission();
- if (sp.getNewPermissions().contains(permName)
- && origPermissions.hasInstallPermission(splitPermName)) {
- upgradedActivityRecognitionPermission = splitPermName;
- newImplicitPermissions.add(permName);
+ // b/210065877: Check that the installed version is pre Q to auto-grant in
+ // case of OS update
+ if (mPackageManagerInt.getInstalledSdkVersion(pkg)
+ < Build.VERSION_CODES.Q) {
+ final List permissionList =
+ getSplitPermissions();
+ int numSplitPerms = permissionList.size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms;
+ splitPermNum++) {
+ SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
+ String splitPermName = sp.getSplitPermission();
+ if (sp.getNewPermissions().contains(permName)
+ && origPermissions.hasInstallPermission(splitPermName)) {
+ upgradedActivityRecognitionPermission = splitPermName;
+ newImplicitPermissions.add(permName);
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for " + friendlyName);
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for " + friendlyName);
+ }
+ break;
}
- break;
}
}
}
From 43192d28fa7dbb413e60636ddb05fed316d1325c Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Thu, 25 Aug 2022 16:23:12 -0400
Subject: [PATCH 077/208] Check rule package name in
ZenModeHelper.addAutomaticRule
instead of checking that of the configuration activity, which is potentially spoofable. The package name is verified to be the same app as the caller by NMS.
This change removes isSystemRule (called only once) in favor of checking the provided package name directly.
Bug: 242537431
Test: ZenModeHelperTest, manual by verifying via provided exploit apk
Change-Id: Ic7f350618c26a613df455a4128c9195f4b424a4d
Merged-In: Ic7f350618c26a613df455a4128c9195f4b424a4d
(cherry picked from commit 3201baad70443854e7630a5c301f8bde573a43f7)
Merged-In: Ic7f350618c26a613df455a4128c9195f4b424a4d
---
.../server/notification/ZenModeHelper.java | 7 +------
.../server/notification/ZenModeHelperTest.java | 16 +++++++++-------
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1c55762f132d..c96aac6e9914 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -305,7 +305,7 @@ public AutomaticZenRule getAutomaticZenRule(String id) {
public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
String reason) {
- if (!isSystemRule(automaticZenRule)) {
+ if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
if (component == null) {
component = getActivityInfo(automaticZenRule.getConfigurationActivity());
@@ -554,11 +554,6 @@ protected void updateDefaultZenRules() {
}
}
- private boolean isSystemRule(AutomaticZenRule rule) {
- return rule.getOwner() != null
- && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
- }
-
private ServiceInfo getServiceInfo(ComponentName owner) {
Intent queryIntent = new Intent();
queryIntent.setComponent(owner);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index a928d4dc592f..88e2c02f63b9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1576,27 +1576,29 @@ public void testAddAutomaticZenRule() {
}
@Test
- public void testAddAutomaticZenRule_beyondSystemLimit() {
+ public void testAddAutomaticZenRule_claimedSystemOwner() {
+ // Make sure anything that claims to have a "system" owner but not actually part of the
+ // system package still gets limited on number of rules
for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
ScheduleInfo si = new ScheduleInfo();
si.startHour = i;
AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
- null,
- new ComponentName("android", "ScheduleConditionProvider"),
+ new ComponentName("android", "ScheduleConditionProvider" + i),
+ null, // configuration activity
ZenModeConfig.toScheduleConditionId(si),
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test");
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
assertNotNull(id);
}
try {
AutomaticZenRule zenRule = new AutomaticZenRule("name",
- null,
- new ComponentName("android", "ScheduleConditionProvider"),
+ new ComponentName("android", "ScheduleConditionProviderFinal"),
+ null, // configuration activity
ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
new ZenPolicy.Builder().build(),
NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test");
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
fail("allowed too many rules to be created");
} catch (IllegalArgumentException e) {
// yay
From 38898034f3edf4a7ef67969bc66d3b48eb7ceac6 Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Mon, 29 Aug 2022 17:40:14 -0400
Subject: [PATCH 078/208] Trim any long string inputs that come in to
AutomaticZenRule
This change both prevents any rules from being unable to be written to disk and also avoids risk of running out of memory while handling all the zen rules.
Bug: 242703460
Bug: 242703505
Bug: 242703780
Bug: 242704043
Bug: 243794204
Test: cts AutomaticZenRuleTest; atest android.app.AutomaticZenRuleTest; manually confirmed each exploit example either saves the rule successfully with a truncated string (in the case of name & conditionId) or may fail to save the rule at all (if the owner/configactivity is invalid). Additionally ran the memory-exhausting PoC without device crashes.
Change-Id: I110172a43f28528dd274b3b346eb29c3796ff2c6
Merged-In: I110172a43f28528dd274b3b346eb29c3796ff2c6
(cherry picked from commit de172ba0d434c940be9e2aad8685719731ab7da2)
(cherry picked from commit 1fcd99f5aa3490431154d1e80b854aafab821345)
Merged-In: I110172a43f28528dd274b3b346eb29c3796ff2c6
---
core/java/android/app/AutomaticZenRule.java | 58 +++++--
.../src/android/app/AutomaticZenRuleTest.java | 153 ++++++++++++++++++
2 files changed, 201 insertions(+), 10 deletions(-)
create mode 100644 core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index a6cd6d511caf..37b336382769 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -47,6 +47,13 @@ public final class AutomaticZenRule implements Parcelable {
private boolean mModified = false;
private String mPkg;
+ /**
+ * The maximum string length for any string contained in this automatic zen rule. This pertains
+ * both to fields in the rule itself (such as its name) and items with sub-fields.
+ * @hide
+ */
+ public static final int MAX_STRING_LENGTH = 1000;
+
/**
* Creates an automatic zen rule.
*
@@ -93,10 +100,10 @@ public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner,
@Nullable ComponentName configurationActivity, @NonNull Uri conditionId,
@Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) {
- this.name = name;
- this.owner = owner;
- this.configurationActivity = configurationActivity;
- this.conditionId = conditionId;
+ this.name = getTrimmedString(name);
+ this.owner = getTrimmedComponentName(owner);
+ this.configurationActivity = getTrimmedComponentName(configurationActivity);
+ this.conditionId = getTrimmedUri(conditionId);
this.interruptionFilter = interruptionFilter;
this.enabled = enabled;
this.mZenPolicy = policy;
@@ -115,12 +122,12 @@ public AutomaticZenRule(String name, ComponentName owner, ComponentName configur
public AutomaticZenRule(Parcel source) {
enabled = source.readInt() == ENABLED;
if (source.readInt() == ENABLED) {
- name = source.readString();
+ name = getTrimmedString(source.readString());
}
interruptionFilter = source.readInt();
conditionId = source.readParcelable(null);
- owner = source.readParcelable(null);
- configurationActivity = source.readParcelable(null);
+ owner = getTrimmedComponentName(source.readParcelable(null));
+ configurationActivity = getTrimmedComponentName(source.readParcelable(null));
creationTime = source.readLong();
mZenPolicy = source.readParcelable(null);
mModified = source.readInt() == ENABLED;
@@ -196,7 +203,7 @@ public long getCreationTime() {
* Sets the representation of the state that causes this rule to become active.
*/
public void setConditionId(Uri conditionId) {
- this.conditionId = conditionId;
+ this.conditionId = getTrimmedUri(conditionId);
}
/**
@@ -211,7 +218,7 @@ public void setInterruptionFilter(@InterruptionFilter int interruptionFilter) {
* Sets the name of this rule.
*/
public void setName(String name) {
- this.name = name;
+ this.name = getTrimmedString(name);
}
/**
@@ -243,7 +250,7 @@ public void setZenPolicy(ZenPolicy zenPolicy) {
* that are not backed by {@link android.service.notification.ConditionProviderService}.
*/
public void setConfigurationActivity(@Nullable ComponentName componentName) {
- this.configurationActivity = componentName;
+ this.configurationActivity = getTrimmedComponentName(componentName);
}
/**
@@ -333,4 +340,35 @@ public AutomaticZenRule[] newArray(int size) {
return new AutomaticZenRule[size];
}
};
+
+ /**
+ * If the package or class name of the provided ComponentName are longer than MAX_STRING_LENGTH,
+ * return a trimmed version that truncates each of the package and class name at the max length.
+ */
+ private static ComponentName getTrimmedComponentName(ComponentName cn) {
+ if (cn == null) return null;
+ return new ComponentName(getTrimmedString(cn.getPackageName()),
+ getTrimmedString(cn.getClassName()));
+ }
+
+ /**
+ * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
+ */
+ private static String getTrimmedString(String input) {
+ if (input != null && input.length() > MAX_STRING_LENGTH) {
+ return input.substring(0, MAX_STRING_LENGTH);
+ }
+ return input;
+ }
+
+ /**
+ * Returns a truncated copy of the Uri by trimming the string representation to the maximum
+ * string length.
+ */
+ private static Uri getTrimmedUri(Uri input) {
+ if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
+ return Uri.parse(getTrimmedString(input.toString()));
+ }
+ return input;
+ }
}
diff --git a/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
new file mode 100644
index 000000000000..282fdad294eb
--- /dev/null
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AutomaticZenRuleTest {
+ private static final String CLASS = "android.app.AutomaticZenRule";
+
+ @Test
+ public void testLongFields_inConstructor() {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+ // test both variants where there's an owner, and where there's a configuration activity
+ AutomaticZenRule rule1 = new AutomaticZenRule(
+ longString, // name
+ new ComponentName("pkg", longString), // owner
+ null, // configuration activity
+ longUri, // conditionId
+ null, // zen policy
+ 0, // interruption filter
+ true); // enabled
+
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ rule1.getConditionId().toString().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getOwner().getClassName().length());
+
+ AutomaticZenRule rule2 = new AutomaticZenRule(
+ longString, // name
+ null, // owner
+ new ComponentName(longString, "SomeClassName"), // configuration activity
+ longUri, // conditionId
+ null, // zen policy
+ 0, // interruption filter
+ false); // enabled
+
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule2.getName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ rule2.getConditionId().toString().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ rule2.getConfigurationActivity().getPackageName().length());
+ }
+
+ @Test
+ public void testLongFields_inSetters() {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+ AutomaticZenRule rule = new AutomaticZenRule(
+ "sensible name",
+ new ComponentName("pkg", "ShortClass"),
+ null,
+ Uri.parse("uri://short"),
+ null, 0, true);
+
+ rule.setName(longString);
+ rule.setConditionId(longUri);
+ rule.setConfigurationActivity(new ComponentName(longString, longString));
+
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule.getName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ rule.getConditionId().toString().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ rule.getConfigurationActivity().getPackageName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ rule.getConfigurationActivity().getClassName().length());
+ }
+
+ @Test
+ public void testLongInputsFromParcel() {
+ // Create a rule with long fields, set directly via reflection so that we can confirm that
+ // a rule with too-long fields that comes in via a parcel has its fields truncated directly.
+ AutomaticZenRule rule = new AutomaticZenRule(
+ "placeholder",
+ new ComponentName("place", "holder"),
+ null,
+ Uri.parse("uri://placeholder"),
+ null, 0, true);
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+ Field name = Class.forName(CLASS).getDeclaredField("name");
+ name.setAccessible(true);
+ name.set(rule, longString);
+ Field conditionId = Class.forName(CLASS).getDeclaredField("conditionId");
+ conditionId.setAccessible(true);
+ conditionId.set(rule, longUri);
+ Field owner = Class.forName(CLASS).getDeclaredField("owner");
+ owner.setAccessible(true);
+ owner.set(rule, new ComponentName(longString, longString));
+ Field configActivity = Class.forName(CLASS).getDeclaredField("configurationActivity");
+ configActivity.setAccessible(true);
+ configActivity.set(rule, new ComponentName(longString, longString));
+ } catch (NoSuchFieldException e) {
+ fail(e.toString());
+ } catch (ClassNotFoundException e) {
+ fail(e.toString());
+ } catch (IllegalAccessException e) {
+ fail(e.toString());
+ }
+
+ Parcel parcel = Parcel.obtain();
+ rule.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ AutomaticZenRule fromParcel = new AutomaticZenRule(parcel);
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, fromParcel.getName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ fromParcel.getConditionId().toString().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ fromParcel.getConfigurationActivity().getPackageName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ fromParcel.getConfigurationActivity().getClassName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ fromParcel.getOwner().getPackageName().length());
+ assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+ fromParcel.getOwner().getClassName().length());
+ }
+}
From a01a298fde349033adba7bf3702168c0717f617b Mon Sep 17 00:00:00 2001
From: Ivan Chiang
Date: Mon, 18 Jul 2022 15:28:46 +0800
Subject: [PATCH 079/208] [RESTRICT AUTOMERGE] Check permission for
VoiceInteraction
The service must have the CAPTURE_AUDIO_HOTWORD permission to access
AlwaysOnHotwordDetector. If it doesn't have the permission, return
STATE_HARDWARE_UNAVAILABLE state. If it is not granted the
RECORD_AUDIO permisison, it also can't start to recognize the audio.
Test: manual
Test: atest CtsVoiceInteractionTestCases
Test: atest CtsAssistTestCases
Bug: 229793943
Change-Id: I7d0f8d2f6af4bc4210060f0a44469db2afc7a1bb
(cherry picked from commit 525690ce16c1c7a48b7880897a4349e2dda0ca09)
Merged-In: I7d0f8d2f6af4bc4210060f0a44469db2afc7a1bb
---
.../voice/AlwaysOnHotwordDetector.java | 57 ++++++++++++++++++-
.../voice/VoiceInteractionService.java | 2 +-
.../VoiceInteractionManagerService.java | 23 ++++++++
3 files changed, 78 insertions(+), 4 deletions(-)
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 6f941121771e..b956d1918f7e 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -16,12 +16,14 @@
package android.service.voice;
+import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.hardware.soundtrigger.KeyphraseMetadata;
@@ -232,8 +234,10 @@ public class AlwaysOnHotwordDetector {
private final Callback mExternalCallback;
private final Object mLock = new Object();
private final Handler mHandler;
+ private final Context mContext;
private int mAvailability = STATE_NOT_READY;
+ private boolean mIsGrantedHotwordPermission;
/**
* A ModelParamRange is a representation of supported parameter range for a
@@ -408,23 +412,37 @@ public static abstract class Callback {
public abstract void onRecognitionResumed();
}
+ private static boolean hasHotwordPermission(Context context) {
+ return context.checkSelfPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean hasRecordAudioPermission(Context context) {
+ return context.checkSelfPermission(Manifest.permission.RECORD_AUDIO)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
/**
+ * @param context The context to check permission
* @param text The keyphrase text to get the detector for.
* @param locale The java locale for the detector.
* @param callback A non-null Callback for receiving the recognition events.
+ * @param keyphraseEnrollmentInfo The Enrollment info of key phrase
* @param modelManagementService A service that allows management of sound models.
* @hide
*/
- public AlwaysOnHotwordDetector(String text, Locale locale, Callback callback,
+ public AlwaysOnHotwordDetector(Context context, String text, Locale locale, Callback callback,
KeyphraseEnrollmentInfo keyphraseEnrollmentInfo,
IVoiceInteractionManagerService modelManagementService) {
mText = text;
+ mContext = context;
mLocale = locale;
mKeyphraseEnrollmentInfo = keyphraseEnrollmentInfo;
mExternalCallback = callback;
mHandler = new MyHandler();
mInternalCallback = new SoundTriggerListener(mHandler);
mModelManagementService = modelManagementService;
+ mIsGrantedHotwordPermission = hasHotwordPermission(mContext);
new RefreshAvailabiltyTask().execute();
}
@@ -477,6 +495,11 @@ private int getSupportedRecognitionModesLocked() {
@AudioCapabilities
public int getSupportedAudioCapabilities() {
if (DBG) Slog.d(TAG, "getSupportedAudioCapabilities()");
+
+ if (!mIsGrantedHotwordPermission) {
+ return 0;
+ }
+
synchronized (mLock) {
return getSupportedAudioCapabilitiesLocked();
}
@@ -515,6 +538,12 @@ private int getSupportedAudioCapabilitiesLocked() {
*/
public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")");
+
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD "
+ + "permissions to access the detector.");
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("startRecognition called on an invalid detector");
@@ -545,6 +574,12 @@ public boolean startRecognition(@RecognitionFlags int recognitionFlags) {
*/
public boolean stopRecognition() {
if (DBG) Slog.d(TAG, "stopRecognition()");
+
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ throw new IllegalStateException("Must have the RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD "
+ + "permissions to access the detector.");
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("stopRecognition called on an invalid detector");
@@ -582,6 +617,10 @@ public int setParameter(@ModelParams int modelParam, int value) {
Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")");
}
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ return SoundTrigger.STATUS_INVALID_OPERATION;
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("setParameter called on an invalid detector");
@@ -609,6 +648,10 @@ public int getParameter(@ModelParams int modelParam) {
Slog.d(TAG, "getParameter(" + modelParam + ")");
}
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ return MODEL_PARAM_THRESHOLD_FACTOR;
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("getParameter called on an invalid detector");
@@ -634,6 +677,10 @@ public ModelParamRange queryParameter(@ModelParams int modelParam) {
Slog.d(TAG, "queryParameter(" + modelParam + ")");
}
+ if (!mIsGrantedHotwordPermission || !hasRecordAudioPermission(mContext)) {
+ return null;
+ }
+
synchronized (mLock) {
if (mAvailability == STATE_INVALID) {
throw new IllegalStateException("queryParameter called on an invalid detector");
@@ -742,8 +789,8 @@ void invalidate() {
*/
void onSoundModelsChanged() {
synchronized (mLock) {
- if (mAvailability == STATE_INVALID
- || mAvailability == STATE_HARDWARE_UNAVAILABLE) {
+ if (mAvailability == STATE_INVALID || mAvailability == STATE_HARDWARE_UNAVAILABLE
+ || !hasRecordAudioPermission(mContext)) {
Slog.w(TAG, "Received onSoundModelsChanged for an unsupported keyphrase/config");
return;
}
@@ -962,6 +1009,10 @@ public Void doInBackground(Void... params) {
* @return The initial availability without checking the enrollment status.
*/
private int internalGetInitialAvailability() {
+ if (!mIsGrantedHotwordPermission) {
+ return STATE_HARDWARE_UNAVAILABLE;
+ }
+
synchronized (mLock) {
// This detector has already been invalidated.
if (mAvailability == STATE_INVALID) {
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 45d3465fdae8..a56d40790dbf 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -318,7 +318,7 @@ public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
synchronized (mLock) {
// Allow only one concurrent recognition via the APIs.
safelyShutdownHotwordDetector();
- mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
+ mHotwordDetector = new AlwaysOnHotwordDetector(this, keyphrase, locale, callback,
mKeyphraseEnrollmentInfo, mSystemService);
}
return mHotwordDetector;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 0abab087b6d8..d70166f02ef9 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1094,6 +1094,9 @@ public KeyphraseMetadata getEnrolledKeyphraseMetadata(String keyphrase,
@Override
public ModuleProperties getDspModuleProperties() {
+ // Allow the call if it is granted CAPTURE_AUDIO_HOTWORD.
+ enforceCallingPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD);
+
// Allow the call if this is the current voice interaction service.
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1110,6 +1113,9 @@ public ModuleProperties getDspModuleProperties() {
@Override
public int startRecognition(int keyphraseId, String bcp47Locale,
IRecognitionStatusCallback callback, RecognitionConfig recognitionConfig) {
+ // Allow the call if it is granted RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD.
+ enforceAlwaysOnHotwordPermissions();
+
// Allow the call if this is the current voice interaction service.
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1145,6 +1151,9 @@ public int startRecognition(int keyphraseId, String bcp47Locale,
@Override
public int stopRecognition(int keyphraseId, IRecognitionStatusCallback callback) {
+ // Allow the call if it is granted RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD.
+ enforceAlwaysOnHotwordPermissions();
+
// Allow the call if this is the current voice interaction service.
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1160,6 +1169,9 @@ public int stopRecognition(int keyphraseId, IRecognitionStatusCallback callback)
@Override
public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ // Allow the call if it is granted RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD.
+ enforceAlwaysOnHotwordPermissions();
+
// Allow the call if this is the current voice interaction service.
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1175,6 +1187,9 @@ public int setParameter(int keyphraseId, @ModelParams int modelParam, int value)
@Override
public int getParameter(int keyphraseId, @ModelParams int modelParam) {
+ // Allow the call if it is granted RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD.
+ enforceAlwaysOnHotwordPermissions();
+
// Allow the call if this is the current voice interaction service.
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1191,6 +1206,9 @@ public int getParameter(int keyphraseId, @ModelParams int modelParam) {
@Override
@Nullable
public ModelParamRange queryParameter(int keyphraseId, @ModelParams int modelParam) {
+ // Allow the call if it is granted RECORD_AUDIO and CAPTURE_AUDIO_HOTWORD.
+ enforceAlwaysOnHotwordPermissions();
+
// Allow the call if this is the current voice interaction service.
synchronized (this) {
enforceIsCurrentVoiceInteractionService();
@@ -1454,6 +1472,11 @@ private boolean isCallerHoldingPermission(String permission) {
== PackageManager.PERMISSION_GRANTED;
}
+ private void enforceAlwaysOnHotwordPermissions() {
+ enforceCallingPermission(Manifest.permission.RECORD_AUDIO);
+ enforceCallingPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD);
+ }
+
private void enforceCallingPermission(String permission) {
if (!isCallerHoldingPermission(permission)) {
throw new SecurityException("Caller does not hold the permission " + permission);
From 3a96ce77f22ebae7deef8c4b7379a18de81707ce Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Tue, 6 Sep 2022 16:14:16 -0400
Subject: [PATCH 080/208] Fix system zen rules by using owner package name if
caller is system
Previously were unable to add new zen rules because rules added via the settings pages were getting registered under package "com.android.settings", which then were not considered "system rules". These rules should have package android, so when we can trust the caller (via checking that the caller is system) we should be taking the package name from the owner of the rule.
Bug: 245236706
Bug: 242537431
Test: NMSTest; manual
Change-Id: Id69b671592396ac3304862dadbe73de328a8e27a
Merged-In: Id69b671592396ac3304862dadbe73de328a8e27a
(cherry picked from commit 0b262d0ae5cd30a8411ca3fafd7919d72b2fa464)
Merged-In: Id69b671592396ac3304862dadbe73de328a8e27a
---
.../NotificationManagerService.java | 11 +++++-
.../NotificationManagerServiceTest.java | 37 +++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 60d7ec51ca09..1cfaf960271f 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4523,7 +4523,16 @@ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg)
}
enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
- return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
+ // If the caller is system, take the package name from the rule's owner rather than
+ // from the caller's package.
+ String rulePkg = pkg;
+ if (isCallingUidSystem()) {
+ if (automaticZenRule.getOwner() != null) {
+ rulePkg = automaticZenRule.getOwner().getPackageName();
+ }
+ }
+
+ return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
"addAutomaticZenRule");
}
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 2239769a3525..f5cf23125c1b 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5936,6 +5936,43 @@ public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Except
mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
}
+ @Test
+ public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
+ mService.isSystemUid = true;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "com.android.settings");
+
+ // verify that zen mode helper gets passed in a package name of "android"
+ verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
+ mService.isSystemUid = false;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "another.package");
+
+ // verify that zen mode helper gets passed in the package name from the arg, not the owner
+ verify(mockZenModeHelper).addAutomaticZenRule(
+ eq("another.package"), eq(rule), anyString());
+ }
+
@Test
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
try {
From d192ab48d0c7096693feef81b5b5bb4221007480 Mon Sep 17 00:00:00 2001
From: Matt Pietal
Date: Thu, 18 Aug 2022 12:04:43 +0000
Subject: [PATCH 081/208] [DO NOT MERGE] Do not dismiss keyguard after SIM PUK
unlock
After PUK unlock, multiple calls to
KeyguardSecurityContainerController#dismiss() were being called from
the KeyguardSimPukViewController, which begins the transition to the
next security screen, if any. At the same time, other parts of the
system, also listening to SIM events, recognize the PUK unlock and
call KeyguardSecurityContainer#showSecurityScreen, which updates which
security method comes next. After boot, this should be one of PIN,
Password, Pattern, assuming they have a security method. If one of the
first dismiss() calls comes AFTER the security method changes, this is
incorrectly recognized by the code as a successful
PIN/pattern/password unlock. This causes the keyguard to be marked as
done, causing screen flickers and incorrect system state.
The solution: every call to dismiss() should include a new parameter
for the security method used. If there is a difference between this
parameter and the current value in KeyguardSecurityContainerCallback,
ignore the request, as the system state has changed.
Bug: 218500036
Test: atest KeyguardSecurityContainerTest
Merged-In: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
Change-Id: I30226bc7b5eda9480d471b35fe81e106b0491ff8
(cherry picked from commit c27cf661a6b14849bd13ba69b5ee40c9066fcf2c)
Merged-In: I30226bc7b5eda9480d471b35fe81e106b0491ff8
---
.../AdminSecondaryLockScreenController.java | 3 +-
.../keyguard/KeyguardAbsKeyInputView.java | 4 ++-
.../android/keyguard/KeyguardHostView.java | 11 +++---
.../com/android/keyguard/KeyguardPINView.java | 6 ++++
.../keyguard/KeyguardPasswordView.java | 6 ++++
.../android/keyguard/KeyguardPatternView.java | 3 +-
.../keyguard/KeyguardSecurityCallback.java | 9 +++--
.../keyguard/KeyguardSecurityContainer.java | 34 +++++++++++++------
.../android/keyguard/KeyguardSimPinView.java | 9 ++++-
.../android/keyguard/KeyguardSimPukView.java | 13 +++++--
...dminSecondaryLockScreenControllerTest.java | 3 +-
11 files changed, 76 insertions(+), 25 deletions(-)
diff --git a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
index e99245fa438f..f9e4340b4fc8 100644
--- a/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
+++ b/packages/SystemUI/src/com/android/keyguard/AdminSecondaryLockScreenController.java
@@ -33,6 +33,7 @@
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import java.util.NoSuchElementException;
@@ -204,7 +205,7 @@ private void dismiss(int userId) {
hide();
if (mKeyguardCallback != null) {
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
- /* bypassSecondaryLockScreen= */true);
+ /* bypassSecondaryLockScreen= */true, SecurityMode.Invalid);
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index bbf71dcaa682..22afd615646d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -30,6 +30,7 @@
import android.view.View;
import android.widget.LinearLayout;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
@@ -99,6 +100,7 @@ protected boolean shouldLockout(long deadline) {
protected abstract int getPasswordTextViewId();
protected abstract void resetState();
+ protected abstract SecurityMode getSecurityMode();
@Override
protected void onFinishInflate() {
@@ -209,7 +211,7 @@ private void onPasswordChecked(int userId, boolean matched, int timeoutMs,
mCallback.reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) {
mDismissing = true;
- mCallback.dismiss(true, userId);
+ mCallback.dismiss(true, userId, getSecurityMode());
}
} else {
if (isValidPassword) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
index 57b3761c294f..b733d1cfc2c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardHostView.java
@@ -87,7 +87,7 @@ public void onTrustGrantedWithFlags(int flags, int userId) {
Log.i(TAG, "TrustAgent dismissed Keyguard.");
}
dismiss(false /* authenticated */, userId,
- /* bypassSecondaryLockScreen */ false);
+ /* bypassSecondaryLockScreen */ false, SecurityMode.Invalid);
} else {
mViewMediatorCallback.playTrustedSound();
}
@@ -193,12 +193,13 @@ public void showErrorMessage(CharSequence message) {
* @return True if the keyguard is done.
*/
public boolean dismiss(int targetUserId) {
- return dismiss(false, targetUserId, false);
+ return dismiss(false, targetUserId, false, getCurrentSecurityMode());
}
public boolean handleBackKey() {
if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
- mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser());
+ mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser(),
+ getCurrentSecurityMode());
return true;
}
return false;
@@ -210,9 +211,9 @@ protected KeyguardSecurityContainer getSecurityContainer() {
@Override
public boolean dismiss(boolean authenticated, int targetUserId,
- boolean bypassSecondaryLockScreen) {
+ boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
- bypassSecondaryLockScreen);
+ bypassSecondaryLockScreen, expectedSecurityMode);
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index a99b1a1aad87..2cdcf9eddaa2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -23,6 +23,7 @@
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.Dependency;
@@ -218,4 +219,9 @@ private void enableClipping(boolean enable) {
public boolean hasOverlappingRendering() {
return false;
}
+
+ @Override
+ public SecurityMode getSecurityMode() {
+ return SecurityMode.PIN;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 97317cf5580f..1a8a26c07d0a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -38,6 +38,7 @@
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R;
import java.util.List;
@@ -387,4 +388,9 @@ public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_password_unlock);
}
+
+ @Override
+ public SecurityMode getSecurityMode() {
+ return SecurityMode.Password;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index d0e8b040f251..921e30ddc249 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -40,6 +40,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockscreenCredential;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils;
@@ -363,7 +364,7 @@ private void onPatternChecked(int userId, boolean matched, int timeoutMs,
mCallback.reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
- mCallback.dismiss(true, userId);
+ mCallback.dismiss(true, userId, SecurityMode.Pattern);
}
} else {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
index e38472745234..bc72f7979a74 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -15,14 +15,17 @@
*/
package com.android.keyguard;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+
public interface KeyguardSecurityCallback {
/**
* Dismiss the given security screen.
* @param securityVerified true if the user correctly entered credentials for the given screen.
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
+ * @param expectedSecurityMode The security mode that is invoking this dismiss.
*/
- void dismiss(boolean securityVerified, int targetUserId);
+ void dismiss(boolean securityVerified, int targetUserId, SecurityMode expectedSecurityMode);
/**
* Dismiss the given security screen.
@@ -30,8 +33,10 @@ public interface KeyguardSecurityCallback {
* @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
* if any, during this dismissal.
+ * @param expectedSecurityMode The security mode that is invoking this dismiss.
*/
- void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen);
+ void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen,
+ SecurityMode expectedSecurityMode);
/**
* Manually report user activity to keep the device awake.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index bace9324ac93..b2020d9fe2d5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -193,7 +193,7 @@ public void onEnd(WindowInsetsAnimation animation) {
// Used to notify the container when something interesting happens.
public interface SecurityCallback {
public boolean dismiss(boolean authenticated, int targetUserId,
- boolean bypassSecondaryLockScreen);
+ boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode);
public void userActivity();
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
@@ -689,11 +689,20 @@ void showPrimarySecurityScreen(boolean turningOff) {
* completion.
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
* secondary lock screen requirement, if any.
+ * @param expectedSecurityMode SecurityMode that is invoking this request. SecurityMode.Invalid
+ * indicates that no check should be done
* @return true if keyguard is done
*/
boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
- boolean bypassSecondaryLockScreen) {
+ boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
+ if (expectedSecurityMode != SecurityMode.Invalid
+ && expectedSecurityMode != getCurrentSecurityMode()) {
+ Log.w(TAG, "Attempted to invoke showNextSecurityScreenOrFinish with securityMode "
+ + expectedSecurityMode + ", but current mode is " + getCurrentSecurityMode());
+ return false;
+ }
+
boolean finish = false;
boolean strongAuth = false;
int eventSubtype = -1;
@@ -832,14 +841,17 @@ public void onUserInput() {
}
@Override
- public void dismiss(boolean authenticated, int targetId) {
- dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
+ public void dismiss(boolean authenticated, int targetId,
+ SecurityMode expectedSecurityMode) {
+ dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false,
+ expectedSecurityMode);
}
@Override
public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen) {
- mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
+ boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
+ mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen,
+ expectedSecurityMode);
}
public boolean isVerifyUnlockOnly() {
@@ -891,10 +903,11 @@ public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { }
@Override
public boolean isVerifyUnlockOnly() { return false; }
@Override
- public void dismiss(boolean securityVerified, int targetUserId) { }
+ public void dismiss(boolean securityVerified, int targetUserId,
+ SecurityMode expectedSecurityMode) { }
@Override
public void dismiss(boolean authenticated, int targetId,
- boolean bypassSecondaryLockScreen) { }
+ boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
@Override
public void onUserInput() { }
@Override
@@ -946,8 +959,9 @@ public SecurityMode getCurrentSecuritySelection() {
return mCurrentSecuritySelection;
}
- public void dismiss(boolean authenticated, int targetUserId) {
- mCallback.dismiss(authenticated, targetUserId);
+ public void dismiss(boolean authenticated, int targetUserId,
+ SecurityMode expectedSecurityMode) {
+ mCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
}
public boolean needsInput() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 76adf04b21e7..6be80c49bd06 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -37,6 +37,7 @@
import android.view.WindowManager;
import android.widget.ImageView;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -348,7 +349,8 @@ public void run() {
mRemainingAttempts = -1;
mShowDefaultMessage = true;
if (mCallback != null) {
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
+ SecurityMode.SimPin);
}
} else {
mShowDefaultMessage = false;
@@ -398,5 +400,10 @@ public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_sim_pin_unlock);
}
+
+ @Override
+ public SecurityMode getSecurityMode() {
+ return SecurityMode.SimPin;
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index a84664ceee3d..0e9b301f03d0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -36,6 +36,7 @@
import android.view.WindowManager;
import android.widget.ImageView;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -76,7 +77,8 @@ public void onSimStateChanged(int subId, int slotId, int simState) {
// mCallback can be null if onSimStateChanged callback is called when keyguard
// isn't active.
if (mCallback != null) {
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
+ SecurityMode.SimPuk);
}
break;
}
@@ -422,8 +424,8 @@ public void run() {
mRemainingAttempts = -1;
mShowDefaultMessage = true;
if (mCallback != null) {
- mCallback.dismiss(true,
- KeyguardUpdateMonitor.getCurrentUser());
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
+ SecurityMode.SimPuk);
}
} else {
mShowDefaultMessage = false;
@@ -479,6 +481,11 @@ public CharSequence getTitle() {
return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_sim_puk_unlock);
}
+
+ @Override
+ public SecurityMode getSecurityMode() {
+ return SecurityMode.SimPuk;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
index 9be2d124026c..3114b0a99e97 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AdminSecondaryLockScreenControllerTest.java
@@ -46,6 +46,7 @@
import androidx.test.filters.SmallTest;
+import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase;
import org.junit.After;
@@ -191,7 +192,7 @@ private SurfaceView verifySurfaceReady() throws Exception {
private void verifyViewDismissed(SurfaceView v) throws Exception {
verify(mParent).removeView(v);
- verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true);
+ verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true, SecurityMode.Invalid);
assertThat(mContext.isBound(mComponentName)).isFalse();
}
}
From 7d9e3b24b1f5b4f9ff8aad4e87fe49db1e19a396 Mon Sep 17 00:00:00 2001
From: Chris Ye
Date: Sun, 10 May 2020 15:07:31 -0700
Subject: [PATCH 082/208] Change InputWindowInfo::isTrustedOverlay() to be
permission and flag based
Add private flag to WindowManager.LayoutParams. If the flag is set,
check if caller has INTERNAL_SYSTEM_WINDOW permission.
Bug: 155781676
Bug: 196389741
Test: atest WindowManagerServiceTests
Change-Id: I70151697cc01e8427129f951f0ebadc4805b2d56
Merged-In: I70151697cc01e8427129f951f0ebadc4805b2d56
(cherry picked from commit 716333761d4298432a3d8822df9161bba14da620)
Merged-In: I70151697cc01e8427129f951f0ebadc4805b2d56
---
core/java/android/view/IWindowSession.aidl | 5 ++--
core/java/android/view/InputWindowHandle.java | 3 +++
core/java/android/view/WindowManager.java | 27 +++++++++++++------
.../android/view/WindowlessWindowManager.java | 12 +++++----
...droid_hardware_input_InputWindowHandle.cpp | 4 +++
.../systemui/bubbles/BubbleController.java | 3 ++-
.../server/policy/WindowManagerPolicy.java | 2 --
.../com/android/server/wm/DisplayPolicy.java | 12 ++++-----
.../java/com/android/server/wm/Session.java | 10 ++++---
.../server/wm/WindowManagerService.java | 15 +++++++----
.../com/android/server/wm/WindowState.java | 21 +++++++++++++++
11 files changed, 81 insertions(+), 33 deletions(-)
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 0410c9024dcb..819e89b67b38 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -336,11 +336,12 @@ interface IWindowSession {
* an input channel where the client can receive input.
*/
void grantInputChannel(int displayId, in SurfaceControl surface, in IWindow window,
- in IBinder hostInputToken, int flags, int type, out InputChannel outInputChannel);
+ in IBinder hostInputToken, int flags, int privateFlags, int type,
+ out InputChannel outInputChannel);
/**
* Update the flags on an input channel associated with a particular surface.
*/
void updateInputChannel(in IBinder channelToken, int displayId, in SurfaceControl surface,
- int flags, in Region region);
+ int flags, int privateFlags, in Region region);
}
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 71d26b8880f7..b3cf78c5157f 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -82,6 +82,9 @@ public final class InputWindowHandle {
// Input event dispatching is paused.
public boolean paused;
+ // Window is trusted overlay.
+ public boolean trustedOverlay;
+
// Id of process and user that owns the window.
public int ownerPid;
public int ownerUid;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 98155de99b6f..eca0045ad436 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1216,14 +1216,6 @@ public static class LayoutParams extends ViewGroup.LayoutParams implements Parce
*/
public static final int TYPE_STATUS_BAR_ADDITIONAL = FIRST_SYSTEM_WINDOW + 41;
- /**
- * Similar to TYPE_APPLICATION_OVERLAY, but trusted to overlay other windows since it is
- * is coming from the system.
- * @hide
- */
- // TODO(b/155781676): Remove and replace call points with trustedOverlay when that is ready.
- public static final int TYPE_TRUSTED_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 42;
-
/**
* End of types of system windows.
*/
@@ -2044,6 +2036,11 @@ public static boolean isSystemAlertWindowType(@WindowType int type) {
*/
public static final int PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME = 0x40000000;
+ /**
+ * Flag to indicate that the window is a trusted overlay.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_TRUSTED_OVERLAY = 0x20000000;
/**
* An internal annotation for flags that can be specified to {@link #softInputMode}.
*
@@ -2952,6 +2949,20 @@ public void setFitInsetsIgnoringVisibility(boolean ignore) {
privateFlags |= PRIVATE_FLAG_FIT_INSETS_CONTROLLED;
}
+ /**
+ * Specifies that the window should be considered a trusted system overlay. Trusted system
+ * overlays are ignored when considering whether windows are obscured during input
+ * dispatch. Requires the {@link android.Manifest.permission.INTERNAL_SYSTEM_WINDOW}
+ * permission.
+ *
+ * {@see android.view.MotionEvent#FLAG_WINDOW_IS_OBSCURED}
+ * {@see android.view.MotionEvent#FLAG_WINDOW_IS_PARTIALLY_OBSCURED}
+ * @hide
+ */
+ public void setTrustedOverlay() {
+ privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
+ }
+
/**
* @return the insets types that this window is avoiding overlapping.
*/
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index f0006d988163..13f26f5a7fb6 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -115,7 +115,8 @@ protected void setTouchRegion(IBinder window, @Nullable Region region) {
if (state.mInputChannelToken != null) {
try {
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId,
- state.mSurfaceControl, state.mParams.flags, state.mInputRegion);
+ state.mSurfaceControl, state.mParams.flags, state.mParams.privateFlags,
+ state.mInputRegion);
} catch (RemoteException e) {
Log.e(TAG, "Failed to update surface input channel: ", e);
}
@@ -144,7 +145,7 @@ public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attr
WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
try {
mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, attrs.flags,
- attrs.type, outInputChannel);
+ attrs.privateFlags, attrs.type, outInputChannel);
} catch (RemoteException e) {
Log.e(TAG, "Failed to grant input to surface: ", e);
}
@@ -274,7 +275,7 @@ public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
&& state.mInputChannelToken != null) {
try {
mRealWm.updateInputChannel(state.mInputChannelToken, state.mDisplayId, sc,
- attrs.flags, state.mInputRegion);
+ attrs.flags, attrs.privateFlags, state.mInputRegion);
} catch (RemoteException e) {
Log.e(TAG, "Failed to update surface input channel: ", e);
}
@@ -445,12 +446,13 @@ public void reportSystemGestureExclusionChanged(android.view.IWindow window,
@Override
public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window,
- IBinder hostInputToken, int flags, int type, InputChannel outInputChannel) {
+ IBinder hostInputToken, int flags, int privateFlags, int type,
+ InputChannel outInputChannel) {
}
@Override
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags, Region region) {
+ int flags, int privateFlags, Region region) {
}
@Override
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 79f62cb19db0..81569e0f7b7a 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -59,6 +59,7 @@ static struct {
jfieldID hasFocus;
jfieldID hasWallpaper;
jfieldID paused;
+ jfieldID trustedOverlay;
jfieldID ownerPid;
jfieldID ownerUid;
jfieldID inputFeatures;
@@ -151,6 +152,7 @@ bool NativeInputWindowHandle::updateInfo() {
gInputWindowHandleClassInfo.hasWallpaper);
mInfo.paused = env->GetBooleanField(obj,
gInputWindowHandleClassInfo.paused);
+ mInfo.trustedOverlay = env->GetBooleanField(obj, gInputWindowHandleClassInfo.trustedOverlay);
mInfo.ownerPid = env->GetIntField(obj,
gInputWindowHandleClassInfo.ownerPid);
mInfo.ownerUid = env->GetIntField(obj,
@@ -329,6 +331,8 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.paused, clazz,
"paused", "Z");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.trustedOverlay, clazz, "trustedOverlay", "Z");
+
GET_FIELD_ID(gInputWindowHandleClassInfo.ownerPid, clazz,
"ownerPid", "I");
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index fb819f04e0e1..e09a05da655f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -758,13 +758,14 @@ private void addToWindowManagerMaybe() {
// themselves.
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
// Start not focusable - we'll become focusable when expanded so the ActivityView
// can use the IME.
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
PixelFormat.TRANSLUCENT);
+ mWmLayoutParams.setTrustedOverlay();
mWmLayoutParams.setFitInsetsTypes(0);
mWmLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
mWmLayoutParams.token = new Binder();
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index cadbe51c8043..684e2c4d5243 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -56,7 +56,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
@@ -796,7 +795,6 @@ default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindo
// in a higher layer than TYPE_APPLICATION_OVERLAY.
return canAddInternalSystemWindow ? 13 : 10;
case TYPE_APPLICATION_OVERLAY:
- case TYPE_TRUSTED_APPLICATION_OVERLAY:
return 12;
case TYPE_INPUT_METHOD:
// on-screen keyboards and other such input method user interfaces go here.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 4f828df3d1e0..1a94ba5ddbf8 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -77,6 +77,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -99,7 +100,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
-import static android.view.WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
@@ -1024,6 +1024,11 @@ int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
}
+ if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
+ mContext.enforcePermission(
+ android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
+ "DisplayPolicy");
+ }
switch (attrs.type) {
case TYPE_STATUS_BAR:
@@ -1069,11 +1074,6 @@ int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int
android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
"DisplayPolicy");
break;
- case TYPE_TRUSTED_APPLICATION_OVERLAY:
- mContext.enforcePermission(
- android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
- "DisplayPolicy");
- break;
case TYPE_STATUS_BAR_PANEL:
return WindowManagerGlobal.ADD_INVALID_TYPE;
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index e2258093dcbe..86cbf3e3afe1 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -662,7 +662,7 @@ boolean hasAlertWindowSurfaces(DisplayContent displayContent) {
@Override
public void grantInputChannel(int displayId, SurfaceControl surface,
- IWindow window, IBinder hostInputToken, int flags, int type,
+ IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
InputChannel outInputChannel) {
if (hostInputToken == null && !mCanAddInternalSystemWindow) {
// Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to
@@ -678,7 +678,8 @@ public void grantInputChannel(int displayId, SurfaceControl surface,
final long identity = Binder.clearCallingIdentity();
try {
mService.grantInputChannel(mUid, mPid, displayId, surface, window, hostInputToken,
- flags, mCanAddInternalSystemWindow ? type : 0, outInputChannel);
+ flags, mCanAddInternalSystemWindow ? privateFlags : 0,
+ mCanAddInternalSystemWindow ? type : 0, outInputChannel);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -686,10 +687,11 @@ public void grantInputChannel(int displayId, SurfaceControl surface,
@Override
public void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags, Region region) {
+ int flags, int privateFlags, Region region) {
final long identity = Binder.clearCallingIdentity();
try {
- mService.updateInputChannel(channelToken, displayId, surface, flags, region);
+ mService.updateInputChannel(channelToken, displayId, surface, flags,
+ mCanAddInternalSystemWindow ? privateFlags : 0, region);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c25fd12266af..c7f9db64d1ed 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -61,6 +61,7 @@
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -8086,7 +8087,7 @@ private int sanitizeFlagSlippery(int flags, String windowName, int callingUid, i
* views.
*/
void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceControl surface,
- IWindow window, IBinder hostInputToken, int flags, int type,
+ IWindow window, IBinder hostInputToken, int flags, int privateFlags, int type,
InputChannel outInputChannel) {
final InputApplicationHandle applicationHandle;
final String name;
@@ -8102,7 +8103,7 @@ void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceCon
}
updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
- name, applicationHandle, flags, type, null /* region */);
+ name, applicationHandle, flags, privateFlags, type, null /* region */);
clientChannel.transferTo(outInputChannel);
clientChannel.dispose();
@@ -8110,7 +8111,8 @@ void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceCon
private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,
int displayId, SurfaceControl surface, String name,
- InputApplicationHandle applicationHandle, int flags, int type, Region region) {
+ InputApplicationHandle applicationHandle, int flags, int privateFlags, int type,
+ Region region) {
InputWindowHandle h = new InputWindowHandle(applicationHandle, displayId);
h.token = channelToken;
h.name = name;
@@ -8139,6 +8141,9 @@ private void updateInputChannel(IBinder channelToken, int callingUid, int callin
h.setTouchableRegionCrop(surface);
}
+ // Check private trusted overlay flag to set trustedOverlay field of input window handle.
+ h.trustedOverlay = (privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0;
+
SurfaceControl.Transaction t = mTransactionFactory.get();
t.setInputWindowInfo(surface, h);
t.apply();
@@ -8152,7 +8157,7 @@ private void updateInputChannel(IBinder channelToken, int callingUid, int callin
* is undefined.
*/
void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surface,
- int flags, Region region) {
+ int flags, int privateFlags, Region region) {
final InputApplicationHandle applicationHandle;
final String name;
final EmbeddedWindowController.EmbeddedWindow win;
@@ -8167,7 +8172,7 @@ void updateInputChannel(IBinder channelToken, int displayId, SurfaceControl surf
}
updateInputChannel(channelToken, win.mOwnerUid, win.mOwnerPid, displayId, surface, name,
- applicationHandle, flags, win.mWindowType, region);
+ applicationHandle, flags, privateFlags, win.mWindowType, region);
}
/** Return whether layer tracing is enabled */
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 522b8d8fcce8..74b5840512d2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -55,11 +55,14 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
@@ -84,6 +87,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -947,6 +951,23 @@ public boolean isInteractive() {
? mActivityRecord.getInputApplicationHandle(false /* update */) : null,
getDisplayId());
+ // Check private trusted overlay flag and window type to set trustedOverlay variable of
+ // input window handle.
+ mInputWindowHandle.trustedOverlay =
+ (mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
+ && mOwnerCanAddInternalSystemWindow;
+ mInputWindowHandle.trustedOverlay |=
+ mAttrs.type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
+ || mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG
+ || mAttrs.type == TYPE_MAGNIFICATION_OVERLAY || mAttrs.type == TYPE_STATUS_BAR
+ || mAttrs.type == TYPE_NOTIFICATION_SHADE
+ || mAttrs.type == TYPE_NAVIGATION_BAR
+ || mAttrs.type == TYPE_NAVIGATION_BAR_PANEL
+ || mAttrs.type == TYPE_SECURE_SYSTEM_OVERLAY
+ || mAttrs.type == TYPE_DOCK_DIVIDER
+ || mAttrs.type == TYPE_ACCESSIBILITY_OVERLAY
+ || mAttrs.type == TYPE_INPUT_CONSUMER;
+
// Make sure we initial all fields before adding to parentWindow, to prevent exception
// during onDisplayChanged.
if (mIsChildWindow) {
From d03d1f514fef88d50098b7eb92b7b285c3d42855 Mon Sep 17 00:00:00 2001
From: Winson Chung
Date: Thu, 15 Jul 2021 10:35:46 -0700
Subject: [PATCH 083/208] Add mechanism for a task's windows to be trusted
overlays
- Exposes a method to set that a certain part of the SF hierarchy is
trusted, and sets this state for tasks in PIP.
Bug: 191529039
Bug: 196389741
Test: Manual, try using permission dialog while PIP is active
Change-Id: I170cb5a7d22ef569eb36de21cc0bcbef60dd385e
Merged-In: I170cb5a7d22ef569eb36de21cc0bcbef60dd385e
(cherry picked from commit 47fb132ef2c4ca2896e9b82c4f004542139b6ad1)
Merged-In: I170cb5a7d22ef569eb36de21cc0bcbef60dd385e
---
core/java/android/view/SurfaceControl.java | 13 +++++++++++
core/jni/android_view_SurfaceControl.cpp | 13 ++++++++++-
.../com/android/server/wm/ActivityStack.java | 2 +-
.../server/wm/RootWindowContainer.java | 22 ++++++++++++++++++-
.../core/java/com/android/server/wm/Task.java | 3 +--
.../android/server/wm/StubTransaction.java | 6 +++++
6 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 87b2f4b46df7..1a4b303bd267 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -139,6 +139,8 @@ private static native void nativeSetBackgroundBlurRadius(long transactionObj, lo
int blurRadius);
private static native void nativeSetLayerStack(long transactionObj, long nativeObject,
int layerStack);
+ private static native void nativeSetTrustedOverlay(long transactionObj, long nativeObject,
+ boolean isTrustedOverlay);
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
@@ -3037,6 +3039,17 @@ public Transaction setFrameRate(@NonNull SurfaceControl sc,
return this;
}
+ /**
+ * Sets the trusted overlay state on this SurfaceControl and it is inherited to all the
+ * children. The caller must hold the ACCESS_SURFACE_FLINGER permission.
+ * @hide
+ */
+ public Transaction setTrustedOverlay(SurfaceControl sc, boolean isTrustedOverlay) {
+ checkPreconditions(sc);
+ nativeSetTrustedOverlay(mNativeObject, sc.mNativeObject, isTrustedOverlay);
+ return this;
+ }
+
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index ae36f8a7b30b..fd2ccbe50b8d 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -627,6 +627,14 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb
transaction->setShadowRadius(ctrl, shadowRadius);
}
+static void nativeSetTrustedOverlay(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jboolean isTrustedOverlay) {
+ auto transaction = reinterpret_cast(transactionObj);
+
+ SurfaceControl* const ctrl = reinterpret_cast(nativeObject);
+ transaction->setTrustedOverlay(ctrl, isTrustedOverlay);
+}
+
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
jfloat frameRate, jint compatibility) {
auto transaction = reinterpret_cast(transactionObj);
@@ -1666,7 +1674,10 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetGlobalShadowSettings },
{"nativeGetHandle", "(J)J",
(void*)nativeGetHandle },
- {"nativeSetFixedTransformHint", "(JJI)V", (void*)nativeSetFixedTransformHint},
+ {"nativeSetFixedTransformHint", "(JJI)V",
+ (void*)nativeSetFixedTransformHint},
+ {"nativeSetTrustedOverlay", "(JJZ)V",
+ (void*)nativeSetTrustedOverlay },
};
int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 071e9a56e5f5..60fdbf9aea1b 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -715,7 +715,7 @@ && isActivityTypeStandardOrUndefined()) {
: WINDOWING_MODE_FULLSCREEN;
}
if (currentMode == WINDOWING_MODE_PINNED) {
- mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
+ mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
if (likelyResolvedMode == WINDOWING_MODE_PINNED
&& taskDisplayArea.getRootPinnedTask() != null) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e240af134435..7dcfaf342174 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2240,7 +2240,27 @@ void moveActivityToPinnedStack(ActivityRecord r, String reason) {
ensureActivitiesVisible(null, 0, false /* preserveWindows */);
resumeFocusedStacksTopActivities();
- mService.getTaskChangeNotificationController().notifyActivityPinned(r);
+ notifyActivityPipModeChanged(r.getTask(), r);
+ }
+
+ /**
+ * Notifies when an activity enters or leaves PIP mode.
+ *
+ * @param task the task of {@param r}
+ * @param r indicates the activity currently in PIP, can be null to indicate no activity is
+ * currently in PIP mode.
+ */
+ void notifyActivityPipModeChanged(@NonNull Task task, @Nullable ActivityRecord r) {
+ final boolean inPip = r != null;
+ if (inPip) {
+ mService.getTaskChangeNotificationController().notifyActivityPinned(r);
+ } else {
+ mService.getTaskChangeNotificationController().notifyActivityUnpinned();
+ }
+ mWindowManager.mPolicy.setPipVisibilityLw(inPip);
+ mWmService.mTransactionFactory.get()
+ .setTrustedOverlay(task.getSurfaceControl(), inPip)
+ .apply();
}
void executeAppTransitionForAllDisplay() {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 0d1a3436d4cc..228b5054c13f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1152,7 +1152,7 @@ void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer ol
&& (newParent == null || !newParent.inPinnedWindowingMode())) {
// Notify if a task from the pinned stack is being removed
// (or moved depending on the mode).
- mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
+ mRootWindowContainer.notifyActivityPipModeChanged(this, null);
}
}
@@ -4649,5 +4649,4 @@ protected boolean isForceHidden() {
long getProtoFieldId() {
return TASK;
}
-
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index d7eedd990f04..4b7e4ec5809a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -277,4 +277,10 @@ public SurfaceControl.Transaction setFixedTransformHint(SurfaceControl sc,
public SurfaceControl.Transaction unsetFixedTransformHint(@NonNull SurfaceControl sc) {
return this;
}
+
+ @Override
+ public SurfaceControl.Transaction setTrustedOverlay(SurfaceControl sc,
+ boolean isTrustedOverlay) {
+ return this;
+ }
}
From b88a2e634e223492a4895c778cae0fa9883902d1 Mon Sep 17 00:00:00 2001
From: Winson Chung
Date: Mon, 4 Oct 2021 21:50:31 +0000
Subject: [PATCH 084/208] DO NOT MERGE: Revert "Map
TYPE_TRUSTED_APPLICATION_OVERLAY to system window type for A11y"
This reverts commit 4ec7b5c3fbd80d38f1010631dfa84c1476f7c867.
Bug: 196389741
Test: Ensure PIP windows are trusted overlays
Change-Id: I49477ffd489ecbc969ab9b9310c2344ab03280e8
(cherry picked from commit 0cf0d420e18ebb88668f01595ef6acfe3b568430)
Merged-In: I49477ffd489ecbc969ab9b9310c2344ab03280e8
---
.../server/accessibility/AccessibilityWindowManager.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index d15c60b9501d..468e93a8f683 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -725,8 +725,7 @@ private int getTypeForWindowManagerWindowType(int windowType) {
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
- case WindowManager.LayoutParams.TYPE_SCREENSHOT:
- case WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY: {
+ case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
From b96861451cab9c516fa0b7009c7391962548d34d Mon Sep 17 00:00:00 2001
From: Vishnu Nair
Date: Wed, 26 Jan 2022 23:25:07 +0000
Subject: [PATCH 085/208] SurfaceControl: Add setDropInputMode api
Introduces an API to drop input events on this SurfaceControl. This
policy will be inherited by its children. The caller must hold the
ACCESS_SURFACE_FLINGER permission.
Options include:
ALL: SurfaceControl and its children will not receive any
input regardless of whether it has a valid input channel.
These policies are used to enable features that allow for a less trusted
interaction model between apps. See the bug for more details.
Note: this backport doesn't include the oclude mode since its not
needed for the security fix.
Test: atest libgui_test InputDispatcherDropInputFeatureTest
Bug: 197296414
Merged-In: Ifcb4133306a43874e74e8fb0f42b60842daf6f25
Change-Id: Ifcb4133306a43874e74e8fb0f42b60842daf6f25
(cherry picked from commit fad4624dd82c6623d34137d051b76603533ddfc0)
Merged-In: Ifcb4133306a43874e74e8fb0f42b60842daf6f25
---
Android.bp | 1 +
core/java/android/view/SurfaceControl.java | 16 ++++++++++++++--
core/jni/android_view_SurfaceControl.cpp | 11 +++++++++++
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/Android.bp b/Android.bp
index fc64efd93234..ad0e6ca2c3d4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -255,6 +255,7 @@ filegroup {
":framework_native_aidl",
":gatekeeper_aidl",
":gsiservice_aidl",
+ ":guiconstants_aidl",
":incidentcompanion_aidl",
":installd_aidl",
":keystore_aidl",
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1a4b303bd267..0dc7f5ad26fb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -42,6 +42,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.gui.DropInputMode;
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayedContentSample;
import android.hardware.display.DisplayedContentSamplingAttributes;
@@ -49,7 +50,6 @@
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.Trace;
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseIntArray;
@@ -141,7 +141,8 @@ private static native void nativeSetLayerStack(long transactionObj, long nativeO
int layerStack);
private static native void nativeSetTrustedOverlay(long transactionObj, long nativeObject,
boolean isTrustedOverlay);
-
+ private static native void nativeSetDropInputMode(
+ long transactionObj, long nativeObject, int flags);
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
private static native boolean nativeClearAnimationFrameStats();
@@ -3050,6 +3051,17 @@ public Transaction setTrustedOverlay(SurfaceControl sc, boolean isTrustedOverlay
return this;
}
+ /**
+ * Sets the input event drop mode on this SurfaceControl and its children. The caller must
+ * hold the ACCESS_SURFACE_FLINGER permission. See {@code InputEventDropMode}.
+ * @hide
+ */
+ public Transaction setDropInputMode(SurfaceControl sc, @DropInputMode int mode) {
+ checkPreconditions(sc);
+ nativeSetDropInputMode(mNativeObject, sc.mNativeObject, mode);
+ return this;
+ }
+
/**
* Merge the other transaction into this transaction, clearing the
* other transaction as if it had been applied.
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index fd2ccbe50b8d..3c704ffb8de7 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -671,6 +671,13 @@ static void nativeSetFixedTransformHint(JNIEnv* env, jclass clazz, jlong transac
transaction->setFixedTransformHint(ctrl, transformHint);
}
+static void nativeSetDropInputMode(JNIEnv* env, jclass clazz, jlong transactionObj,
+ jlong nativeObject, jint mode) {
+ auto transaction = reinterpret_cast(transactionObj);
+ SurfaceControl* const ctrl = reinterpret_cast(nativeObject);
+ transaction->setDropInputMode(ctrl, static_cast(mode));
+}
+
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
jlongArray array = env->NewLongArray(displayIds.size());
@@ -1495,6 +1502,7 @@ static jlong nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
+ // clang-format off
{"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJLandroid/os/Parcel;)J",
(void*)nativeCreate },
{"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
@@ -1678,6 +1686,9 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetFixedTransformHint},
{"nativeSetTrustedOverlay", "(JJZ)V",
(void*)nativeSetTrustedOverlay },
+ {"nativeSetDropInputMode", "(JJI)V",
+ (void*)nativeSetDropInputMode},
+ // clang-format on
};
int register_android_view_SurfaceControl(JNIEnv* env)
From 51ad6b15bfaad7c26dffbb3c7124421a8bbf692d Mon Sep 17 00:00:00 2001
From: Vishnu Nair
Date: Wed, 2 Feb 2022 17:13:21 +0000
Subject: [PATCH 086/208] Drop input for toast and child surfaces
Toasts that do not have the trustedOverlay flag should not receive input.
These windows should not have any children, so force this hierarchy of
windows to drop all input by setting a flag on the toast window state
which will apply the DROP_INPUT flag on all windows with an input
channel. This is to prevent malicious apps from parenting surfaces with
input channels to the toast window.
Test: show toast and check if input feature flag DROP_INPUT id set via dumpsys
Bug: b/197296414
Change-Id: I316b76b685ca5030fd8aa91283555efcce4d6994
Merged-In: I316b76b685ca5030fd8aa91283555efcce4d6994
(cherry picked from commit 55c1473bf2fedaacf7bb8ac068e6f9b1a625b5e0)
Merged-In: I316b76b685ca5030fd8aa91283555efcce4d6994
---
.../java/com/android/server/wm/DisplayPolicy.java | 15 +++++++++++++++
.../android/server/wm/WindowManagerService.java | 1 +
2 files changed, 16 insertions(+)
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1a94ba5ddbf8..179777a1cf34 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -149,6 +149,7 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.gui.DropInputMode;
import android.hardware.input.InputManager;
import android.hardware.power.V1_0.PowerHint;
import android.os.Handler;
@@ -993,6 +994,20 @@ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams att
}
}
+ /**
+ * Add additional policy if needed to ensure the window or its children should not receive any
+ * input.
+ */
+ public void setDropInputModePolicy(WindowState win, LayoutParams attrs) {
+ if (attrs.type == TYPE_TOAST
+ && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
+ // Toasts should not receive input. These windows should not have any children, so
+ // force this hierarchy of windows to drop all input.
+ mService.mTransactionFactory.get()
+ .setDropInputMode(win.getSurfaceControl(), DropInputMode.ALL).apply();
+ }
+ }
+
/**
* @return {@code true} if the calling activity initiate toast and is visible with
* {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c7f9db64d1ed..565dc710b6bf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1656,6 +1656,7 @@ public int addWindow(Session session, IWindow client, int seq,
win.mToken.addWindow(win);
displayPolicy.addWindowLw(win, attrs);
+ displayPolicy.setDropInputModePolicy(win, win.mAttrs);
if (type == TYPE_INPUT_METHOD) {
displayContent.setInputMethodWindowLocked(win);
imMayMove = false;
From 9bf7153fcbfc19de358cbf1d3a4b2743b5806772 Mon Sep 17 00:00:00 2001
From: Oli Lan
Date: Tue, 19 Jul 2022 10:46:00 +0000
Subject: [PATCH 087/208] Revert "Prevent non-admin users from deleting system
apps."
This reverts commit 6c870e157994519094e9e50ddf93e57a26779e22.
Reason for revert: Regression, DELETE_SYSTEM_APP flag no longer works
Change-Id: Id3eb9e08a5404e88c39235d0d47337ed41bc6139
Merged-In: I4e959e296cca9bbdfc8fccc5e5e0e654ca524165
(cherry picked from commit d9089fbe06e77f5ea1773f5d69b641a81e0b5832)
Merged-In: Id3eb9e08a5404e88c39235d0d47337ed41bc6139
From 6778ac255d58888378e7cc9c839926c64639e693 Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Fri, 19 Aug 2022 09:54:23 -0400
Subject: [PATCH 088/208] Limit the size of NotificationChannel and
NotificationChannelGroup
Test: android.app.NotificationChannelGroupTest
Test: android.app.NotificationChannelTest
Test: cts NotificationChannelTest
Test: cts NotificationChannelGroupTest
Bug: 241764350
Bug: 241764340
Bug: 241764135
Bug: 242702935
Bug: 242703118
Bug: 242703202
Bug: 242702851
Bug: 242703217
Bug: 242703556
Change-Id: I0925583ab54d6c81c415859618f6b907ab7baada
(cherry picked from commit 3850857cb0e7f26702d5bd601731d7290390fa3b)
(cherry picked from commit 6d417539d705bc757ac4923bc4da878af327c812)
Merged-In: I0925583ab54d6c81c415859618f6b907ab7baada
---
.../java/android/app/NotificationChannel.java | 23 ++--
.../android/app/NotificationChannelGroup.java | 10 +-
.../app/NotificationChannelGroupTest.java | 73 ++++++++++++
.../android/app/NotificationChannelTest.java | 106 ++++++++++++++++++
4 files changed, 201 insertions(+), 11 deletions(-)
create mode 100644 core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
create mode 100644 core/tests/coretests/src/android/app/NotificationChannelTest.java
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index cf2f7690bc2c..cd46b39574d2 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -78,8 +78,13 @@ public final class NotificationChannel implements Parcelable {
/**
* The maximum length for text fields in a NotificationChannel. Fields will be truncated at this
* limit.
+ * @hide
*/
- private static final int MAX_TEXT_LENGTH = 1000;
+ public static final int MAX_TEXT_LENGTH = 1000;
+ /**
+ * @hide
+ */
+ public static final int MAX_VIBRATION_LENGTH = 1000;
private static final String TAG_CHANNEL = "channel";
private static final String ATT_NAME = "name";
@@ -236,17 +241,17 @@ public NotificationChannel(String id, CharSequence name, @Importance int importa
*/
protected NotificationChannel(Parcel in) {
if (in.readByte() != 0) {
- mId = in.readString();
+ mId = getTrimmedString(in.readString());
} else {
mId = null;
}
if (in.readByte() != 0) {
- mName = in.readString();
+ mName = getTrimmedString(in.readString());
} else {
mName = null;
}
if (in.readByte() != 0) {
- mDesc = in.readString();
+ mDesc = getTrimmedString(in.readString());
} else {
mDesc = null;
}
@@ -255,18 +260,22 @@ protected NotificationChannel(Parcel in) {
mLockscreenVisibility = in.readInt();
if (in.readByte() != 0) {
mSound = Uri.CREATOR.createFromParcel(in);
+ mSound = Uri.parse(getTrimmedString(mSound.toString()));
} else {
mSound = null;
}
mLights = in.readByte() != 0;
mVibration = in.createLongArray();
+ if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) {
+ mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH);
+ }
mUserLockedFields = in.readInt();
mFgServiceShown = in.readByte() != 0;
mVibrationEnabled = in.readByte() != 0;
mShowBadge = in.readByte() != 0;
mDeleted = in.readByte() != 0;
if (in.readByte() != 0) {
- mGroup = in.readString();
+ mGroup = getTrimmedString(in.readString());
} else {
mGroup = null;
}
@@ -276,8 +285,8 @@ protected NotificationChannel(Parcel in) {
mAllowBubbles = in.readInt();
mImportanceLockedByOEM = in.readBoolean();
mOriginalImportance = in.readInt();
- mParentId = in.readString();
- mConversationId = in.readString();
+ mParentId = getTrimmedString(in.readString());
+ mConversationId = getTrimmedString(in.readString());
mDemoted = in.readBoolean();
mImportantConvo = in.readBoolean();
}
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 403fb3e3727c..526c0491f03f 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -42,8 +42,9 @@ public final class NotificationChannelGroup implements Parcelable {
/**
* The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at
* this limit.
+ * @hide
*/
- private static final int MAX_TEXT_LENGTH = 1000;
+ public static final int MAX_TEXT_LENGTH = 1000;
private static final String TAG_GROUP = "channelGroup";
private static final String ATT_NAME = "name";
@@ -89,13 +90,14 @@ public NotificationChannelGroup(String id, CharSequence name) {
*/
protected NotificationChannelGroup(Parcel in) {
if (in.readByte() != 0) {
- mId = in.readString();
+ mId = getTrimmedString(in.readString());
} else {
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mName = getTrimmedString(mName.toString());
if (in.readByte() != 0) {
- mDescription = in.readString();
+ mDescription = getTrimmedString(in.readString());
} else {
mDescription = null;
}
@@ -119,7 +121,7 @@ public void writeToParcel(Parcel dest, int flags) {
} else {
dest.writeByte((byte) 0);
}
- TextUtils.writeToParcel(mName, dest, flags);
+ TextUtils.writeToParcel(mName.toString(), dest, flags);
if (mDescription != null) {
dest.writeByte((byte) 1);
dest.writeString(mDescription);
diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
new file mode 100644
index 000000000000..2a3da05eabb3
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationChannelGroupTest {
+ private final String CLASS = "android.app.NotificationChannelGroup";
+
+ @Test
+ public void testLongStringFields() {
+ NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", "groupName");
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Field mName = Class.forName(CLASS).getDeclaredField("mName");
+ mName.setAccessible(true);
+ mName.set(group, longString);
+ Field mId = Class.forName(CLASS).getDeclaredField("mId");
+ mId.setAccessible(true);
+ mId.set(group, longString);
+ Field mDescription = Class.forName(CLASS).getDeclaredField("mDescription");
+ mDescription.setAccessible(true);
+ mDescription.set(group, longString);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ Parcel parcel = Parcel.obtain();
+ group.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup fromParcel =
+ NotificationChannelGroup.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getId().length());
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getName().length());
+ assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH,
+ fromParcel.getDescription().length());
+ }
+}
diff --git a/core/tests/coretests/src/android/app/NotificationChannelTest.java b/core/tests/coretests/src/android/app/NotificationChannelTest.java
new file mode 100644
index 000000000000..647bfe84231d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationChannelTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import static junit.framework.TestCase.assertEquals;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationChannelTest {
+ private final String CLASS = "android.app.NotificationChannel";
+
+ @Test
+ public void testLongStringFields() {
+ NotificationChannel channel = new NotificationChannel("id", "name", 3);
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Field mName = Class.forName(CLASS).getDeclaredField("mName");
+ mName.setAccessible(true);
+ mName.set(channel, longString);
+ Field mId = Class.forName(CLASS).getDeclaredField("mId");
+ mId.setAccessible(true);
+ mId.set(channel, longString);
+ Field mDesc = Class.forName(CLASS).getDeclaredField("mDesc");
+ mDesc.setAccessible(true);
+ mDesc.set(channel, longString);
+ Field mParentId = Class.forName(CLASS).getDeclaredField("mParentId");
+ mParentId.setAccessible(true);
+ mParentId.set(channel, longString);
+ Field mGroup = Class.forName(CLASS).getDeclaredField("mGroup");
+ mGroup.setAccessible(true);
+ mGroup.set(channel, longString);
+ Field mConversationId = Class.forName(CLASS).getDeclaredField("mConversationId");
+ mConversationId.setAccessible(true);
+ mConversationId.set(channel, longString);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+
+ Parcel parcel = Parcel.obtain();
+ channel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getId().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getName().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getDescription().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getParentChannelId().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getGroup().length());
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getConversationId().length());
+ }
+
+ @Test
+ public void testLongAlertFields() {
+ NotificationChannel channel = new NotificationChannel("id", "name", 3);
+
+ channel.setSound(Uri.parse("content://" + Strings.repeat("A",65536)),
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channel.setVibrationPattern(new long[65550/2]);
+
+ Parcel parcel = Parcel.obtain();
+ channel.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel);
+ assertEquals(NotificationChannel.MAX_VIBRATION_LENGTH,
+ fromParcel.getVibrationPattern().length);
+ assertEquals(NotificationChannel.MAX_TEXT_LENGTH,
+ fromParcel.getSound().toString().length());
+ }
+}
From fcd7769c4f6906ee1a4ff928a81069a143e29a09 Mon Sep 17 00:00:00 2001
From: Oli Lan
Date: Tue, 9 Aug 2022 17:48:15 +0100
Subject: [PATCH 089/208] Prevent non-admin users from deleting system apps.
This addresses a security issue where the guest user can remove updates
for system apps.
With this CL, attempts to uninstall/downgrade system apps will fail if
attempted by a non-admin user, unless the DELETE_SYSTEM_APP flag is
specified.
This is a fixed version of ag/17408864, to address b/236578018.
Bug: 170646036
Test: manual, try uninstalling system app update as guest
Merged-In: I4e959e296cca9bbdfc8fccc5e5e0e654ca524165
Change-Id: I6ecfef50294c9000a6ce539bdec6f372c872a40b
(cherry picked from commit fbfa268d47c7915b7a87d3fef22a5b8f3bbabeb7)
Merged-In: I6ecfef50294c9000a6ce539bdec6f372c872a40b
---
.../core/java/com/android/server/pm/PackageManagerService.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4c5e966f54c0..7fe821fa43e3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18653,7 +18653,8 @@ int deletePackageX(String packageName, long versionCode, int userId, int deleteF
return PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
- if (isSystemApp(uninstalledPs)) {
+ if (isSystemApp(uninstalledPs)
+ && (deleteFlags & PackageManager.DELETE_SYSTEM_APP) == 0) {
UserInfo userInfo = mUserManager.getUserInfo(userId);
if (userInfo == null || !userInfo.isAdmin()) {
Slog.w(TAG, "Not removing package " + packageName
From dfcfbbf1ebaa7b517981a389c8507762227f7295 Mon Sep 17 00:00:00 2001
From: Daniel Norman
Date: Thu, 1 Sep 2022 10:14:24 -0700
Subject: [PATCH 090/208] Include all enabled services when FEEDBACK_ALL_MASK.
Bug: 243849844
Test: m sts;
sts-tradefed run sts-dynamic-develop -m CtsAccessibilityTestCases
Change-Id: I4f93e06d1066085bd64e8f09882de2f4a72a0633
(cherry picked from commit 2bc4d49c2b0265f5de1c62d1342b1426cc5e1377)
Merged-In: I4f93e06d1066085bd64e8f09882de2f4a72a0633
---
.../server/accessibility/AccessibilityManagerService.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 75fcc4c490ea..4d4a98606db0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -791,7 +791,8 @@ public List getEnabledAccessibilityServiceList(int fee
final List result = new ArrayList<>(serviceCount);
for (int i = 0; i < serviceCount; ++i) {
final AccessibilityServiceConnection service = services.get(i);
- if ((service.mFeedbackType & feedbackType) != 0) {
+ if ((service.mFeedbackType & feedbackType) != 0
+ || feedbackType == AccessibilityServiceInfo.FEEDBACK_ALL_MASK) {
result.add(service.getServiceInfo());
}
}
From 773e4d07355b761f5979321b3c1e17d47d9f0e38 Mon Sep 17 00:00:00 2001
From: Songchun Fan
Date: Fri, 9 Sep 2022 14:50:31 -0700
Subject: [PATCH 091/208] [pm] forbid deletion of protected packages
BUG: 242996180
Test: adb shell pm uninstall --user 0 com.google.android.apps.work.oobconfig
Test: Verified with the command above. Before this CL, the package can
be deleted. After this CL, the deletion will fail.
Change-Id: Iba408e536b340ea5d66ab499442c0c4f828fa36f
(cherry picked from commit 15f85c7fa97fe9faa540e6ad9e850990f46a5cca)
Merged-In: Iba408e536b340ea5d66ab499442c0c4f828fa36f
(cherry picked from commit fcdc62081c934d35a55ff7e511590337cb4e277a)
Merged-In: Iba408e536b340ea5d66ab499442c0c4f828fa36f
---
.../android/server/pm/PackageManagerService.java | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7fe821fa43e3..d4897a0cc9ad 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18292,6 +18292,20 @@ private void deletePackageVersionedInternal(VersionedPackage versionedPackage,
final String packageName = versionedPackage.getPackageName();
final long versionCode = versionedPackage.getLongVersionCode();
+
+ if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ mHandler.post(() -> {
+ try {
+ Slog.w(TAG, "Attempted to delete protected package: " + packageName);
+ observer.onPackageDeleted(packageName,
+ PackageManager.DELETE_FAILED_INTERNAL_ERROR, null);
+ } catch (RemoteException re) {
+ }
+ });
+ return;
+ }
+
+
final String internalPackageName;
try {
From 63af641843c72e0a3f463ec708a1160f0a61f647 Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Tue, 6 Sep 2022 10:19:06 -0400
Subject: [PATCH 092/208] Fix NPE
Test: NotificationChannelGroupTest
Test: view notification settings for an app that doesn't use groups
Fixes: 244574602
Bug: 241764350
Bug: 241764340
Bug: 241764135
Bug: 242702935
Bug: 242703118
Bug: 242703202
Bug: 242702851
Bug: 242703217
Bug: 242703556
Change-Id: I9c681106f6d645e62b0e44903d40aa523fee0e95
(cherry picked from commit 6f02c07176d0fa4d6985c8f2200ccf49a1657d1c)
(cherry picked from commit ad30b85784354a21fb915d47d4dc3ef8828d5d3b)
Merged-In: I9c681106f6d645e62b0e44903d40aa523fee0e95
---
.../android/app/NotificationChannelGroup.java | 14 +++++++++++---
.../app/NotificationChannelGroupTest.java | 16 ++++++++++++++++
2 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 526c0491f03f..07802a220015 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -94,8 +94,11 @@ protected NotificationChannelGroup(Parcel in) {
} else {
mId = null;
}
- mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mName = getTrimmedString(mName.toString());
+ if (in.readByte() != 0) {
+ mName = getTrimmedString(in.readString());
+ } else {
+ mName = "";
+ }
if (in.readByte() != 0) {
mDescription = getTrimmedString(in.readString());
} else {
@@ -121,7 +124,12 @@ public void writeToParcel(Parcel dest, int flags) {
} else {
dest.writeByte((byte) 0);
}
- TextUtils.writeToParcel(mName.toString(), dest, flags);
+ if (mName != null) {
+ dest.writeByte((byte) 1);
+ dest.writeString(mName.toString());
+ } else {
+ dest.writeByte((byte) 0);
+ }
if (mDescription != null) {
dest.writeByte((byte) 1);
dest.writeString(mDescription);
diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
index 2a3da05eabb3..625c66a4c60e 100644
--- a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
+++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java
@@ -17,9 +17,11 @@
package android.app;
import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
import android.os.Parcel;
import android.test.AndroidTestCase;
+import android.text.TextUtils;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -70,4 +72,18 @@ public void testLongStringFields() {
assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH,
fromParcel.getDescription().length());
}
+
+ @Test
+ public void testNullableFields() {
+ NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", null);
+
+ Parcel parcel = Parcel.obtain();
+ group.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ NotificationChannelGroup fromParcel =
+ NotificationChannelGroup.CREATOR.createFromParcel(parcel);
+ assertEquals(group.getId(), fromParcel.getId());
+ assertTrue(TextUtils.isEmpty(fromParcel.getName()));
+ }
}
From 6eede71244f2b44ebeba9825f12a98da15ab30cb Mon Sep 17 00:00:00 2001
From: Pinyao Ting
Date: Thu, 14 Jul 2022 11:25:54 -0700
Subject: [PATCH 093/208] Fix a security issue in app widget service.
Bug: 234013191
Test: atest RemoteViewsAdapterTest
Change-Id: Icd2eccb7a90124aca18a3dd463c3f79e3a595c20
Merged-In: Icd2eccb7a90124aca18a3dd463c3f79e3a595c20
(cherry picked from commit 263d7d0ba8818c471a27938c4e002bae33569f01)
(cherry picked from commit 0ee21ef3e652c78c934d257632a4951bd6d38011)
Merged-In: Icd2eccb7a90124aca18a3dd463c3f79e3a595c20
---
core/java/android/appwidget/AppWidgetManager.java | 4 +++-
.../com/android/server/appwidget/AppWidgetServiceImpl.java | 7 ++++---
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 009ec522e436..287331aa6d6e 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -1109,7 +1109,9 @@ public void setBindAppWidgetPermission(String packageName, int userId, boolean p
* @param intent The intent of the service which will be providing the data to the
* RemoteViewsAdapter.
* @param connection The callback interface to be notified when a connection is made or lost.
- * @param flags Flags used for binding to the service
+ * @param flags Flags used for binding to the service. Currently only
+ * {@link Context#BIND_AUTO_CREATE} and
+ * {@link Context#BIND_FOREGROUND_SERVICE_WHILE_AWAKE} are supported.
*
* @see Context#getServiceDispatcher(ServiceConnection, Handler, int)
* @hide
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index d7a3a32f102a..f989f73b11b1 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1315,11 +1315,12 @@ public boolean bindRemoteViewsService(String callingPackage, int appWidgetId, In
try {
// Ask ActivityManager to bind it. Notice that we are binding the service with the
// caller app instead of DevicePolicyManagerService.
- if(ActivityManager.getService().bindService(
+ if (ActivityManager.getService().bindService(
caller, activtiyToken, intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
- connection, flags, mContext.getOpPackageName(),
- widget.provider.getUserId()) != 0) {
+ connection, flags & (Context.BIND_AUTO_CREATE
+ | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE),
+ mContext.getOpPackageName(), widget.provider.getUserId()) != 0) {
// Add it to the mapping of RemoteViewsService to appWidgetIds so that we
// can determine when we can call back to the RemoteViewsService later to
From 7a5f25f05b15e4b154ff34a5daa045bc3617f98e Mon Sep 17 00:00:00 2001
From: Jeff Chang
Date: Wed, 14 Sep 2022 16:10:04 +0800
Subject: [PATCH 094/208] [RESTRICT AUTOMERGE] Allow activity to be reparent
while allowTaskReparenting is applied
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Any malicious application could hijack tasks by
android:allowTaskReparenting. This vulnerability can perform UI
spoofing or spying on user’s activities.
This CL only allows activities to be reparent while
android:allowTaskReparenting is applied and the affinity of activity
is same with the target task.
Bug: 240663194
Test: atest IntentTests
Change-Id: I73abb9ec05af95bc14f887ae825a9ada9600f771
(cherry picked from commit 7da08c6bd31584744e91eb6b3914166344ecae33)
Merged-In: I73abb9ec05af95bc14f887ae825a9ada9600f771
---
.../core/java/com/android/server/wm/ResetTargetTaskHelper.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 32de699eaae9..bf206a3a6bff 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -148,15 +148,16 @@ private boolean processActivity(ActivityRecord r, boolean isTargetTask) {
return false;
} else {
- mResultActivities.add(r);
if (r.resultTo != null) {
// If this activity is sending a reply to a previous activity, we can't do
// anything with it now until we reach the start of the reply chain.
// NOTE: that we are assuming the result is always to the previous activity,
// which is almost always the case but we really shouldn't count on.
+ mResultActivities.add(r);
return false;
} else if (mTargetTaskFound && allowTaskReparenting && mTargetTask.affinity != null
&& mTargetTask.affinity.equals(r.taskAffinity)) {
+ mResultActivities.add(r);
// This activity has an affinity for our task. Either remove it if we are
// clearing or move it over to our task. Note that we currently punt on the case
// where we are resetting a task that is not at the top but who has activities
From 3477648bc7543d755f54f458181657419ceefe40 Mon Sep 17 00:00:00 2001
From: Matt Pietal
Date: Wed, 14 Sep 2022 18:05:29 +0000
Subject: [PATCH 095/208] [DO NOT MERGE] Update window with FLAG_SECURE when
bouncer is showing
This will prevent bouncer interactions from showing up in
screenrecords or screenshots.
Fixes: 215005011
Test: atest NotificationShadeWindowControllerImpl && take screenshot
with bouncer up
Merged-In: I3f59df865dc2dd13d4b9ac54bb2dacb7b23f0aa1
Change-Id: Icde7849a181ce8e0c1074537f6dde897aedd8bb3
(cherry picked from commit bc2146966bd931b18ef0a0243508a49be70e7d0b)
Merged-In: Icde7849a181ce8e0c1074537f6dde897aedd8bb3
---
.../NotificationShadeWindowController.java | 11 +++++++++
...NotificationShadeWindowControllerTest.java | 24 ++++++++++++++++++-
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
index 806854dbba0d..523e490eb9c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowController.java
@@ -31,6 +31,7 @@
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Handler;
+import android.os.Build;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.Trace;
@@ -280,6 +281,16 @@ private void applyKeyguardFlags(State state) {
}
Trace.setCounter("display_mode_id", mLpChanged.preferredDisplayModeId);
}
+
+ if (state.mBouncerShowing && !isDebuggable()) {
+ mLpChanged.flags |= LayoutParams.FLAG_SECURE;
+ } else {
+ mLpChanged.flags &= ~LayoutParams.FLAG_SECURE;
+ }
+ }
+
+ protected boolean isDebuggable() {
+ return Build.IS_DEBUGGABLE;
}
private void adjustScreenOrientation(State state) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
index 8c37cf1514fd..6bdc13fa7d59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerTest.java
@@ -18,6 +18,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.google.common.truth.Truth.assertThat;
@@ -83,7 +84,12 @@ public void setUp() {
mNotificationShadeWindowController = new NotificationShadeWindowController(mContext,
mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
mConfigurationController, mKeyguardViewMediator, mKeyguardBypassController,
- mColorExtractor, mDumpManager);
+ mColorExtractor, mDumpManager) {
+ @Override
+ protected boolean isDebuggable() {
+ return false;
+ }
+ };
mNotificationShadeWindowController.setNotificationShadeView(mNotificationShadeWindowView);
mNotificationShadeWindowController.attach();
@@ -183,4 +189,20 @@ public void setKeyguardShowing_notFocusable_byDefault() {
assertThat((mLayoutParameters.getValue().flags & FLAG_NOT_FOCUSABLE) != 0).isTrue();
assertThat((mLayoutParameters.getValue().flags & FLAG_ALT_FOCUSABLE_IM) == 0).isTrue();
}
+
+ @Test
+ public void setKeyguardShowing_enablesSecureFlag() {
+ mNotificationShadeWindowController.setBouncerShowing(true);
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_SECURE) != 0).isTrue();
+ }
+
+ @Test
+ public void setKeyguardNotShowing_disablesSecureFlag() {
+ mNotificationShadeWindowController.setBouncerShowing(false);
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat((mLayoutParameters.getValue().flags & FLAG_SECURE) == 0).isTrue();
+ }
}
From 0df01d7ce2f948ab9583b08f590fa78ac63cc393 Mon Sep 17 00:00:00 2001
From: Pinyao Ting
Date: Wed, 21 Sep 2022 23:06:31 +0000
Subject: [PATCH 096/208] [Do Not Merge] Ignore malformed shortcuts
After an app publishes a shortcut that contains malformed intent, the
system can be stuck in boot-loop due to uncaught exception caused by
parsing the malformed intent.
This CL ignores that particular malformed entry. Since shortcuts are
constantly writes back into the xml from system memory, the malformed
entry will be removed from the xml the next time system persists
shortcuts from memory to file system.
Bug: 246540168
Change-Id: I97d5979fc22ad50d0b36db9cc85099b2f28f6109
Test: manual
(cherry picked from commit a8fe41afb0a89979386ffd17213eb7b5f1c3739d)
Merged-In: I97d5979fc22ad50d0b36db9cc85099b2f28f6109
---
.../com/android/server/pm/ShortcutPackage.java | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 9e27f65105eb..f2bfb2aa1405 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1798,11 +1798,15 @@ public static ShortcutPackage loadFromXml(ShortcutService s, ShortcutUser shortc
continue;
case TAG_SHORTCUT:
- final ShortcutInfo si = parseShortcut(parser, packageName,
- shortcutUser.getUserId(), fromBackup);
-
- // Don't use addShortcut(), we don't need to save the icon.
- ret.mShortcuts.put(si.getId(), si);
+ try {
+ final ShortcutInfo si = parseShortcut(parser, packageName,
+ shortcutUser.getUserId(), fromBackup);
+ // Don't use addShortcut(), we don't need to save the icon.
+ ret.mShortcuts.put(si.getId(), si);
+ } catch (Exception e) {
+ // b/246540168 malformed shortcuts should be ignored
+ Slog.e(TAG, "Failed parsing shortcut.", e);
+ }
continue;
case TAG_SHARE_TARGET:
ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
From 2c62e7161415e5dd8e6bd1e7f27f5a1bf74fe0f2 Mon Sep 17 00:00:00 2001
From: Rhed Jao
Date: Mon, 26 Sep 2022 21:35:26 +0800
Subject: [PATCH 097/208] [DO NOT MERGE] Fix permanent denial of service via
setComponentEnabledSetting
Do not update invalid component enabled settings to prevent the
malicious apps from exhausting system server memory.
Bug: 240936919
Test: atest android.security.cts.PackageManagerTest
Change-Id: I08165337895e89f13a2b9fcce1201cba9ad13d7d
(cherry picked from commit 5e98f267592775a2b886ccaa752377d6967f9741)
Merged-In: I08165337895e89f13a2b9fcce1201cba9ad13d7d
---
.../core/java/com/android/server/pm/PackageManagerService.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d4897a0cc9ad..a01451ee8771 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -21255,6 +21255,9 @@ && checkPermission(Manifest.permission.SUSPEND_APPS, packageName, userId)
} else {
Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
+ className + " does not exist in " + packageName);
+ // Safetynet logging for b/240936919
+ EventLog.writeEvent(0x534e4554, "240936919", callingUid);
+ return;
}
}
switch (newState) {
From 495da93d6a4e3c3ed23783d3ec6a14d155bf3483 Mon Sep 17 00:00:00 2001
From: Hao Ke
Date: Tue, 4 Oct 2022 19:43:58 +0000
Subject: [PATCH 098/208] Add safety checks on KEY_INTENT mismatch.
For many years, Parcel mismatch typed exploits has been using the
AccoungManagerService's passing of KEY_INTENT workflow, as a foothold of
launching arbitrary intents. We are adding an extra check on the service
side to simulate the final deserialization of the KEY_INTENT value, to
make sure the client side won't get a mismatched KEY_INTENT value.
Bug: 250588548
Bug: 240138294
Test: atest CtsAccountManagerTestCases
Test: local test, also see b/250588548
Change-Id: I433e34f6e21ce15c89825044a15b1dec46bb25cc
(cherry picked from commit eb9a0566a583fa13f8aff671c41f78a9e33eab82)
Merged-In: I433e34f6e21ce15c89825044a15b1dec46bb25cc
---
.../accounts/AccountManagerService.java | 34 ++++++++++++++++---
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e24030188c62..ad41c129e96a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -87,6 +87,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -3022,7 +3023,7 @@ public void onResult(Bundle result) {
*/
if (!checkKeyIntent(
Binder.getCallingUid(),
- intent)) {
+ result)) {
onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
"invalid intent in bundle returned");
return;
@@ -3433,7 +3434,7 @@ public void onResult(Bundle result) {
&& (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
- intent)) {
+ result)) {
onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
"invalid intent in bundle returned");
return;
@@ -4784,7 +4785,13 @@ IAccountManagerResponse getResponseAndClose() {
* into launching arbitrary intents on the device via by tricking to click authenticator
* supplied entries in the system Settings app.
*/
- protected boolean checkKeyIntent(int authUid, Intent intent) {
+ protected boolean checkKeyIntent(int authUid, Bundle bundle) {
+ if (!checkKeyIntentParceledCorrectly(bundle)) {
+ EventLog.writeEvent(0x534e4554, "250588548", authUid, "");
+ return false;
+ }
+
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
// Explicitly set an empty ClipData to ensure that we don't offer to
// promote any Uris contained inside for granting purposes
if (intent.getClipData() == null) {
@@ -4821,6 +4828,25 @@ protected boolean checkKeyIntent(int authUid, Intent intent) {
}
}
+ /**
+ * Simulate the client side's deserialization of KEY_INTENT value, to make sure they don't
+ * violate our security policy.
+ *
+ * In particular we want to make sure the Authenticator doesn't trick users
+ * into launching arbitrary intents on the device via exploiting any other Parcel read/write
+ * mismatch problems.
+ */
+ private boolean checkKeyIntentParceledCorrectly(Bundle bundle) {
+ Parcel p = Parcel.obtain();
+ p.writeBundle(bundle);
+ p.setDataPosition(0);
+ Bundle simulateBundle = p.readBundle();
+ p.recycle();
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ Intent simulateIntent = simulateBundle.getParcelable(AccountManager.KEY_INTENT);
+ return (intent.filterEquals(simulateIntent));
+ }
+
private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
String className = activityInfo.name;
return "android".equals(activityInfo.packageName) &&
@@ -4967,7 +4993,7 @@ public void onResult(Bundle result) {
&& (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
if (!checkKeyIntent(
Binder.getCallingUid(),
- intent)) {
+ result)) {
onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
"invalid intent in bundle returned");
return;
From b4a40e447ba7361c63822b98ad4ed178ab9ec499 Mon Sep 17 00:00:00 2001
From: Oli Lan
Date: Fri, 19 Aug 2022 17:08:13 +0100
Subject: [PATCH 099/208] Validate package name passed to
setApplicationRestrictions.
This adds validation that the package name passed to
setApplicationRestrictions is in the correct format. This will avoid
an issue where a path could be entered resulting in a file being
written to an unexpected place.
Bug: 239701237
Test: atest UserManagerServiceTest
Change-Id: I1ab2b7228470f10ec26fe3a608ae540cfc9e9a96
(cherry picked from commit 31a582490d6e8952d24f267df47d669e3861cf67)
Merged-In: I1ab2b7228470f10ec26fe3a608ae540cfc9e9a96
(cherry picked from commit cfcfe6ca8c545f78603c05e23687f8638fd4b51d)
(cherry picked from commit 527146512051626bbcbd6e3590c47ceca2e404ab)
Merged-In: I1ab2b7228470f10ec26fe3a608ae540cfc9e9a96
---
.../android/server/pm/UserManagerService.java | 41 +++++++++++++++++++
.../server/pm/UserManagerServiceTest.java | 7 ++++
2 files changed, 48 insertions(+)
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9576dc567c3f..7307cf24a044 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -88,6 +88,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -4123,6 +4124,13 @@ public Bundle getApplicationRestrictionsForUser(String packageName, @UserIdInt i
public void setApplicationRestrictions(String packageName, Bundle restrictions,
@UserIdInt int userId) {
checkSystemOrRoot("set application restrictions");
+ String validationResult = validateName(packageName);
+ if (validationResult != null) {
+ if (packageName.contains("../")) {
+ EventLog.writeEvent(0x534e4554, "239701237", -1, "");
+ }
+ throw new IllegalArgumentException("Invalid package name: " + validationResult);
+ }
if (restrictions != null) {
restrictions.setDefusable(true);
}
@@ -4149,6 +4157,39 @@ public void setApplicationRestrictions(String packageName, Bundle restrictions,
mContext.sendBroadcastAsUser(changeIntent, UserHandle.of(userId));
}
+ /**
+ * Check if the given name is valid.
+ *
+ * Note: the logic is taken from FrameworkParsingPackageUtils in master, edited to remove
+ * unnecessary parts. Copied here for a security fix.
+ *
+ * @param name The name to check.
+ * @return null if it's valid, error message if not
+ */
+ @VisibleForTesting
+ static String validateName(String name) {
+ final int n = name.length();
+ boolean front = true;
+ for (int i = 0; i < n; i++) {
+ final char c = name.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ front = false;
+ continue;
+ }
+ if (!front) {
+ if ((c >= '0' && c <= '9') || c == '_') {
+ continue;
+ }
+ if (c == '.') {
+ front = true;
+ continue;
+ }
+ }
+ return "bad character '" + c + "'";
+ }
+ return null;
+ }
+
private int getUidForPackage(String packageName) {
long ident = Binder.clearCallingIdentity();
try {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 6c1c019f504e..658f168b608b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -86,6 +86,13 @@ public void testUserSystemPackageWhitelist() throws Exception {
}
}
+ public void testValidateName() {
+ assertNull(UserManagerService.validateName("android"));
+ assertNull(UserManagerService.validateName("com.company.myapp"));
+ assertNotNull(UserManagerService.validateName("/../../data"));
+ assertNotNull(UserManagerService.validateName("/dir"));
+ }
+
private Bundle createBundle() {
Bundle result = new Bundle();
// Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
From 42928a5390ca4f2602206f25f30dfbc727cefd8a Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Mon, 7 Nov 2022 19:06:17 +0000
Subject: [PATCH 100/208] [DO NOT MERGE] Revert "Check rule package name in
ZenModeHelper.addAutomaticRule"
This reverts commit 3201baad70443854e7630a5c301f8bde573a43f7.
Reason for revert: broke DND schedules in multi-user mode b/257477671
Change-Id: Ic92180e5fb02796dc0dc2051aa3d3be6e446886e
(cherry picked from commit 2643890445797097409a900a295ff8431a41a06a)
Merged-In: Ic92180e5fb02796dc0dc2051aa3d3be6e446886e
---
.../server/notification/ZenModeHelper.java | 7 ++++-
.../notification/ZenModeHelperTest.java | 30 -------------------
2 files changed, 6 insertions(+), 31 deletions(-)
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index c96aac6e9914..1c55762f132d 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -305,7 +305,7 @@ public AutomaticZenRule getAutomaticZenRule(String id) {
public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
String reason) {
- if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
+ if (!isSystemRule(automaticZenRule)) {
PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
if (component == null) {
component = getActivityInfo(automaticZenRule.getConfigurationActivity());
@@ -554,6 +554,11 @@ protected void updateDefaultZenRules() {
}
}
+ private boolean isSystemRule(AutomaticZenRule rule) {
+ return rule.getOwner() != null
+ && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
+ }
+
private ServiceInfo getServiceInfo(ComponentName owner) {
Intent queryIntent = new Intent();
queryIntent.setComponent(owner);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 88e2c02f63b9..fcf4d88f7c90 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1575,36 +1575,6 @@ public void testAddAutomaticZenRule() {
assertEquals(zenRule.getName(), ruleInConfig.name);
}
- @Test
- public void testAddAutomaticZenRule_claimedSystemOwner() {
- // Make sure anything that claims to have a "system" owner but not actually part of the
- // system package still gets limited on number of rules
- for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
- ScheduleInfo si = new ScheduleInfo();
- si.startHour = i;
- AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
- new ComponentName("android", "ScheduleConditionProvider" + i),
- null, // configuration activity
- ZenModeConfig.toScheduleConditionId(si),
- new ZenPolicy.Builder().build(),
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
- assertNotNull(id);
- }
- try {
- AutomaticZenRule zenRule = new AutomaticZenRule("name",
- new ComponentName("android", "ScheduleConditionProviderFinal"),
- null, // configuration activity
- ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
- new ZenPolicy.Builder().build(),
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
- String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
- fail("allowed too many rules to be created");
- } catch (IllegalArgumentException e) {
- // yay
- }
- }
-
private void setupZenConfig() {
mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
From 1ef401685310d924ced578e1e53d0040b1cd251f Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Mon, 7 Nov 2022 19:05:55 +0000
Subject: [PATCH 101/208] [DO NOT MERGE] Revert "Fix system zen rules by using
owner package name if caller is system"
This reverts commit 0b262d0ae5cd30a8411ca3fafd7919d72b2fa464.
Reason for revert: broke DND schedules in multi-user mode b/257477671
Change-Id: I6f89dd0406b6815a94e6b37c029601dfc315b1f8
(cherry picked from commit 8de098ee2f6f75a6e280476378b64ea38fe4f114)
Merged-In: I6f89dd0406b6815a94e6b37c029601dfc315b1f8
---
.../NotificationManagerService.java | 11 +-----
.../NotificationManagerServiceTest.java | 37 -------------------
2 files changed, 1 insertion(+), 47 deletions(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 1cfaf960271f..60d7ec51ca09 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4523,16 +4523,7 @@ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg)
}
enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
- // If the caller is system, take the package name from the rule's owner rather than
- // from the caller's package.
- String rulePkg = pkg;
- if (isCallingUidSystem()) {
- if (automaticZenRule.getOwner() != null) {
- rulePkg = automaticZenRule.getOwner().getPackageName();
- }
- }
-
- return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
+ return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
"addAutomaticZenRule");
}
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 f5cf23125c1b..2239769a3525 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5936,43 +5936,6 @@ public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Except
mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
}
- @Test
- public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
- mService.isSystemUid = true;
- ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
- when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
- .thenReturn(true);
- mService.setZenHelper(mockZenModeHelper);
- ComponentName owner = new ComponentName("android", "ProviderName");
- ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
- boolean isEnabled = true;
- AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
- zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
- mBinderService.addAutomaticZenRule(rule, "com.android.settings");
-
- // verify that zen mode helper gets passed in a package name of "android"
- verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
- }
-
- @Test
- public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
- mService.isSystemUid = false;
- ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
- when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
- .thenReturn(true);
- mService.setZenHelper(mockZenModeHelper);
- ComponentName owner = new ComponentName("android", "ProviderName");
- ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
- boolean isEnabled = true;
- AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
- zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
- mBinderService.addAutomaticZenRule(rule, "another.package");
-
- // verify that zen mode helper gets passed in the package name from the arg, not the owner
- verify(mockZenModeHelper).addAutomaticZenRule(
- eq("another.package"), eq(rule), anyString());
- }
-
@Test
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
try {
From e464f83c3e179895dd0bb14726cca6558d066215 Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Tue, 13 Sep 2022 12:53:19 -0400
Subject: [PATCH 102/208] Limit lengths of fields in Condition to a max length.
This app-generated input needs to not be too long to avoid errors in the process of writing to disk.
Bug: 242846316
Test: cts ConditionTest; atest ConditionTest; manually verified exploit apk is OK
Change-Id: Ic2fa8f06cc7a4c1f262115764fbd1be2a226b4b9
Merged-In: Ic2fa8f06cc7a4c1f262115764fbd1be2a226b4b9
(cherry picked from commit 81352c3775949c622441e10b468766441e35edc7)
(cherry picked from commit 80c0fcf06d5a862c4b05be9896a5d320d2f71fb2)
Merged-In: Ic2fa8f06cc7a4c1f262115764fbd1be2a226b4b9
---
.../service/notification/Condition.java | 38 ++++++-
.../service/notification/ConditionTest.java | 101 ++++++++++++++++++
2 files changed, 135 insertions(+), 4 deletions(-)
create mode 100644 core/tests/coretests/src/android/service/notification/ConditionTest.java
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index cf57e2590c9c..0057d3e872ed 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -89,6 +89,12 @@ public final class Condition implements Parcelable {
public final int flags;
public final int icon;
+ /**
+ * The maximum string length for any string contained in this condition.
+ * @hide
+ */
+ public static final int MAX_STRING_LENGTH = 1000;
+
/**
* An object representing the current state of a {@link android.app.AutomaticZenRule}.
* @param id the {@link android.app.AutomaticZenRule#getConditionId()} of the zen rule
@@ -103,16 +109,19 @@ public Condition(Uri id, String summary, String line1, String line2, int icon,
if (id == null) throw new IllegalArgumentException("id is required");
if (summary == null) throw new IllegalArgumentException("summary is required");
if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
- this.id = id;
- this.summary = summary;
- this.line1 = line1;
- this.line2 = line2;
+ this.id = getTrimmedUri(id);
+ this.summary = getTrimmedString(summary);
+ this.line1 = getTrimmedString(line1);
+ this.line2 = getTrimmedString(line2);
this.icon = icon;
this.state = state;
this.flags = flags;
}
public Condition(Parcel source) {
+ // This constructor passes all fields directly into the constructor that takes all the
+ // fields as arguments; that constructor will trim each of the input strings to
+ // max length if necessary.
this((Uri)source.readParcelable(Condition.class.getClassLoader()),
source.readString(),
source.readString(),
@@ -239,4 +248,25 @@ public Condition[] newArray(int size) {
return new Condition[size];
}
};
+
+ /**
+ * Returns a truncated copy of the string if the string is longer than MAX_STRING_LENGTH.
+ */
+ private static String getTrimmedString(String input) {
+ if (input != null && input.length() > MAX_STRING_LENGTH) {
+ return input.substring(0, MAX_STRING_LENGTH);
+ }
+ return input;
+ }
+
+ /**
+ * Returns a truncated copy of the Uri by trimming the string representation to the maximum
+ * string length.
+ */
+ private static Uri getTrimmedUri(Uri input) {
+ if (input != null && input.toString().length() > MAX_STRING_LENGTH) {
+ return Uri.parse(getTrimmedString(input.toString()));
+ }
+ return input;
+ }
}
diff --git a/core/tests/coretests/src/android/service/notification/ConditionTest.java b/core/tests/coretests/src/android/service/notification/ConditionTest.java
new file mode 100644
index 000000000000..42629ba41287
--- /dev/null
+++ b/core/tests/coretests/src/android/service/notification/ConditionTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.notification;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.net.Uri;
+import android.os.Parcel;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.base.Strings;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ConditionTest {
+ private static final String CLASS = "android.service.notification.Condition";
+
+ @Test
+ public void testLongFields_inConstructors() {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+ // Confirm strings are truncated via short constructor
+ Condition cond1 = new Condition(longUri, longString, Condition.STATE_TRUE);
+
+ assertEquals(Condition.MAX_STRING_LENGTH, cond1.id.toString().length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond1.summary.length());
+
+ // Confirm strings are truncated via long constructor
+ Condition cond2 = new Condition(longUri, longString, longString, longString,
+ -1, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_ALWAYS);
+
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.id.toString().length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.summary.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.line1.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, cond2.line2.length());
+ }
+
+ @Test
+ public void testLongFields_viaParcel() {
+ // Set fields via reflection to force them to be long, then parcel and unparcel to make sure
+ // it gets truncated upon unparcelling.
+ Condition cond = new Condition(Uri.parse("uri://placeholder"), "placeholder",
+ Condition.STATE_TRUE);
+
+ try {
+ String longString = Strings.repeat("A", 65536);
+ Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+ Field id = Class.forName(CLASS).getDeclaredField("id");
+ id.setAccessible(true);
+ id.set(cond, longUri);
+ Field summary = Class.forName(CLASS).getDeclaredField("summary");
+ summary.setAccessible(true);
+ summary.set(cond, longString);
+ Field line1 = Class.forName(CLASS).getDeclaredField("line1");
+ line1.setAccessible(true);
+ line1.set(cond, longString);
+ Field line2 = Class.forName(CLASS).getDeclaredField("line2");
+ line2.setAccessible(true);
+ line2.set(cond, longString);
+ } catch (NoSuchFieldException e) {
+ fail(e.toString());
+ } catch (ClassNotFoundException e) {
+ fail(e.toString());
+ } catch (IllegalAccessException e) {
+ fail(e.toString());
+ }
+
+ Parcel parcel = Parcel.obtain();
+ cond.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ Condition fromParcel = new Condition(parcel);
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.id.toString().length());
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.summary.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line1.length());
+ assertEquals(Condition.MAX_STRING_LENGTH, fromParcel.line2.length());
+ }
+}
From 7b6fd9cb5139f1b9d42df0e1f98696a5fe5e7bac Mon Sep 17 00:00:00 2001
From: William Loh
Date: Tue, 30 Aug 2022 00:11:15 +0000
Subject: [PATCH 103/208] Limit length and number of MIME types you can set
Limit character length of MIME types to 255. If this length is exceeded
then a IllegalArugmentException is thrown. The number of MIME types that
can be set is also limited to 500 per MIME group with the number of
total MIME Groups also limited to 500. A IllegalStateException is thrown if this number is exceeded.
Bug: 237291548
Test: Installed and ran POC app from b/237291548
Change-Id: I1d57e674f778cfacdc89225ac3273c432a39af63
Merged-In: I1d57e674f778cfacdc89225ac3273c432a39af63
(cherry picked from commit 3ae3406b9706163073c282a8c4081faa32b606b2)
Merged-In: I1d57e674f778cfacdc89225ac3273c432a39af63
---
.../android/content/pm/parsing/ParsingPackageImpl.java | 3 +++
.../core/java/com/android/server/pm/PackageSetting.java | 9 +++++++++
2 files changed, 12 insertions(+)
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 295107a06f99..707523a192f0 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -1584,6 +1584,9 @@ private void addMimeGroupsFromComponent(ParsedComponent component) {
for (int i = component.getIntents().size() - 1; i >= 0; i--) {
IntentFilter filter = component.getIntents().get(i);
for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) {
+ if (mimeGroups != null && mimeGroups.size() > 500) {
+ throw new IllegalStateException("Max limit on number of MIME Groups reached");
+ }
mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
}
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 432d7f335ebc..d3f557d18178 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -242,11 +242,20 @@ public boolean isMatch(int flags) {
}
public boolean setMimeGroup(String mimeGroup, List mimeTypes) {
+ for (String mimeType : mimeTypes) {
+ if (mimeType.length() > 255) {
+ throw new IllegalArgumentException("MIME type length exceeds 255 characters");
+ }
+ }
ArraySet oldMimeTypes = getMimeGroupInternal(mimeGroup);
if (oldMimeTypes == null) {
throw new IllegalArgumentException("Unknown MIME group " + mimeGroup
+ " for package " + name);
}
+ if (mimeTypes.size() > 500) {
+ throw new IllegalStateException("Max limit on MIME types for MIME group "
+ + mimeGroup + " exceeded for package " + name);
+ }
ArraySet newMimeTypes = new ArraySet<>(mimeTypes);
boolean hasChanges = !newMimeTypes.equals(oldMimeTypes);
From 8a5a68d4bd6232a57d56d1bec40ca20675998ab9 Mon Sep 17 00:00:00 2001
From: Daniel Norman
Date: Wed, 5 Oct 2022 16:28:20 -0700
Subject: [PATCH 104/208] Disable all A11yServices from an uninstalled package.
Previous logic would exit the loop after removing the first service
matching the uninstalled package.
Bug: 243378132
Test: atest AccessibilityEndToEndTest
Test: m sts;
sts-tradefed run sts-dynamic-develop -m \
CtsAccessibilityServiceTestCases
Change-Id: I4ba30345d8600674ee8a9ea3ff411aecbf3655a3
(cherry picked from commit e1f343acdeeddd9a08c9f6c832faf788ce101763)
Merged-In: I4ba30345d8600674ee8a9ea3ff411aecbf3655a3
---
.../AccessibilityManagerService.java | 24 ++++++++++---------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4d4a98606db0..03a44131bdd2 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -456,25 +456,27 @@ public void onPackageRemoved(String packageName, int uid) {
userState.mBindingServices.removeIf(filter);
userState.mCrashedServices.removeIf(filter);
final Iterator it = userState.mEnabledServices.iterator();
+ boolean anyServiceRemoved = false;
while (it.hasNext()) {
final ComponentName comp = it.next();
final String compPkg = comp.getPackageName();
if (compPkg.equals(packageName)) {
it.remove();
- // Update the enabled services setting.
- persistComponentNamesToSettingLocked(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- userState.mEnabledServices, userId);
- // Update the touch exploration granted services setting.
userState.mTouchExplorationGrantedServices.remove(comp);
- persistComponentNamesToSettingLocked(
- Settings.Secure.
- TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
- userState.mTouchExplorationGrantedServices, userId);
- onUserStateChangedLocked(userState);
- return;
+ anyServiceRemoved = true;
}
}
+ if (anyServiceRemoved) {
+ // Update the enabled services setting.
+ persistComponentNamesToSettingLocked(
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userState.mEnabledServices, userId);
+ // Update the touch exploration granted services setting.
+ persistComponentNamesToSettingLocked(
+ Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
+ userState.mTouchExplorationGrantedServices, userId);
+ onUserStateChangedLocked(userState);
+ }
}
}
From f607871aaad9030838143e9bff60006c59792235 Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Wed, 12 Oct 2022 14:27:46 +0000
Subject: [PATCH 105/208] [DO NOT MERGE] Fix conditionId string trimming in
AutomaticZenRule
This change only applies to S branches and earlier.
Bug: 253085433
Bug: 242703460
Bug: 242703505
Bug: 242703780
Bug: 242704043
Bug: 243794204
Test: AutomaticZenRuleTest
Change-Id: Iae423d93b777df8946ecf1c3baf640fcf74990ec
Merged-In: Iae423d93b777df8946ecf1c3baf640fcf74990ec
(cherry picked from commit 83d23fb275d2bcfb090a9c6efd6c71a5f519372f)
Merged-In: Iae423d93b777df8946ecf1c3baf640fcf74990ec
---
core/java/android/app/AutomaticZenRule.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 37b336382769..9a92515ee794 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -125,7 +125,7 @@ public AutomaticZenRule(Parcel source) {
name = getTrimmedString(source.readString());
}
interruptionFilter = source.readInt();
- conditionId = source.readParcelable(null);
+ conditionId = getTrimmedUri(source.readParcelable(null));
owner = getTrimmedComponentName(source.readParcelable(null));
configurationActivity = getTrimmedComponentName(source.readParcelable(null));
creationTime = source.readLong();
From ce52917dfd80ef1c1d36c6433a554e3e7e9fd9d5 Mon Sep 17 00:00:00 2001
From: Nate Myren
Date: Thu, 22 Sep 2022 15:23:24 -0700
Subject: [PATCH 106/208] RESTRICT AUTOMERGE Validate permission tree size on
permission update
Bug: 242537498
Test: manual
Change-Id: I15343e84c1802d6b89249106263319a6539fa73b
Merged-In: I15343e84c1802d6b89249106263319a6539fa73b
(cherry picked from commit 8fdf4530aac096d87c8d6afe64036f972a3835be)
Merged-In: I15343e84c1802d6b89249106263319a6539fa73b
---
.../android/server/pm/permission/PermissionManagerService.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 663f6ebcd73a..e99163c09b1c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -610,8 +610,8 @@ public boolean addPermission(PermissionInfo info, boolean async) {
BasePermission bp = mSettings.getPermissionLocked(info.name);
added = bp == null;
int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
+ enforcePermissionCapLocked(info, tree);
if (added) {
- enforcePermissionCapLocked(info, tree);
bp = new BasePermission(info.name, tree.getSourcePackageName(),
BasePermission.TYPE_DYNAMIC);
} else if (!bp.isDynamic()) {
From 681c53fb8f30b67df6df06bc50bfb761a34b5ead Mon Sep 17 00:00:00 2001
From: Louis Chang
Date: Wed, 28 Sep 2022 06:46:29 +0000
Subject: [PATCH 107/208] [RESTRICT AUTOMERGE] Trim the activity info of
another uid if no privilege
The activity info could be from another uid which is different
from the app that hosts the task. The information should be
trimmed if the caller app doesn't have the privilege.
Bug: 243130512
Test: verified locally
Test: atest RecentTasksTest
Change-Id: Ia343ac70e5bb9aeae718fca6674e1ca491a14512
(cherry picked from commit 401e782b244bf84fd5aab371f60c2e52d6226fb3)
(cherry picked from commit 17df433a3d96fb6c00dc7078fd0f8048645ace6a)
Merged-In: Ia343ac70e5bb9aeae718fca6674e1ca491a14512
---
.../com/android/server/wm/AppTaskImpl.java | 2 +-
.../com/android/server/wm/RecentTasks.java | 8 +++++--
.../com/android/server/wm/RunningTasks.java | 4 ++++
.../core/java/com/android/server/wm/Task.java | 21 +++++++++++++++++++
4 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index dd1d55b2d54d..2fd5963d653b 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -84,7 +84,7 @@ public ActivityManager.RecentTaskInfo getTaskInfo() {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
return mService.getRecentTasks().createRecentTaskInfo(task,
- false /* stripExtras */);
+ false /* stripExtras */, true /* getTasksAllowed */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 3fe75a4ab49e..6151b1892fda 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -962,7 +962,7 @@ private ArrayList getRecentTasksImpl(int maxNum,
continue;
}
- res.add(createRecentTaskInfo(task, true /* stripExtras */));
+ res.add(createRecentTaskInfo(task, true /* stripExtras */, getTasksAllowed));
}
return res;
}
@@ -1834,12 +1834,16 @@ void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
/**
* Creates a new RecentTaskInfo from a Task.
*/
- ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
+ ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras,
+ boolean getTasksAllowed) {
ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
tr.fillTaskInfo(rti, stripExtras);
// Fill in some deprecated values
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
+ if (!getTasksAllowed) {
+ Task.trimIneffectiveInfo(tr, rti);
+ }
return rti;
}
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 3509ba72d058..3c7917bb05d1 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -129,6 +129,10 @@ private RunningTaskInfo createRunningTaskInfo(Task task) {
final RunningTaskInfo rti = task.getTaskInfo();
// Fill in some deprecated values
rti.id = rti.taskId;
+
+ if (!mAllowed) {
+ Task.trimIneffectiveInfo(task, rti);
+ }
return rti;
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 228b5054c13f..c0e4262863e6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3653,6 +3653,27 @@ void fillTaskInfo(TaskInfo info, boolean stripExtras) {
: SCREEN_ORIENTATION_UNSET;
}
+ /**
+ * Removes the activity info if the activity belongs to a different uid, which is
+ * different from the app that hosts the task.
+ */
+ static void trimIneffectiveInfo(Task task, TaskInfo info) {
+ final ActivityRecord baseActivity = task.getActivity(r -> !r.finishing,
+ false /* traverseTopToBottom */);
+ final int baseActivityUid =
+ baseActivity != null ? baseActivity.getUid() : task.effectiveUid;
+
+ if (info.topActivityInfo != null
+ && task.effectiveUid != info.topActivityInfo.applicationInfo.uid) {
+ info.topActivity = null;
+ info.topActivityInfo = null;
+ }
+
+ if (task.effectiveUid != baseActivityUid) {
+ info.baseActivity = null;
+ }
+ }
+
/**
* Returns a {@link TaskInfo} with information from this task.
*/
From 9b5d4851e2dec09778c1fb9e673f7a3081da118f Mon Sep 17 00:00:00 2001
From: Nate Myren
Date: Fri, 23 Sep 2022 12:04:57 -0700
Subject: [PATCH 108/208] RESTRICT AUTOMERGE Revoke SYSTEM_ALERT_WINDOW on
upgrade past api 23
Bug: 221040577
Test: atest PermissionTest23#testPre23AppsWithSystemAlertWindowGetDeniedOnUpgrade
Change-Id: I4b4605aaae107875811070dea6d031c5d9f25c96
(cherry picked from commit 14551ab6d2c754d83d6b504549aabb40018d9c6a)
Merged-In: I4b4605aaae107875811070dea6d031c5d9f25c96
---
.../server/pm/PackageManagerService.java | 4 +-
.../permission/PermissionManagerService.java | 60 +++++++++++++++----
.../PermissionManagerServiceInternal.java | 29 +++------
3 files changed, 57 insertions(+), 36 deletions(-)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a01451ee8771..9d3cb7012590 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -12605,9 +12605,7 @@ private void commitPackageSettings(AndroidPackage pkg,
AsyncTask.execute(() -> {
if (hasOldPkg) {
- mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
- allPackageNames);
- mPermissionManager.revokeStoragePermissionsIfScopeExpanded(pkg, oldPkg);
+ mPermissionManager.onPackageUpdated(pkg, oldPkg, allPackageNames);
}
if (hasPermissionDefinitionChanges) {
mPermissionManager.revokeRuntimePermissionsIfPermissionDefinitionChanged(
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 e99163c09b1c..0a98b8b0df57 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2321,6 +2321,46 @@ private void revokeStoragePermissionsIfScopeExpanded(
}
+ /**
+ * If the package was below api 23, got the SYSTEM_ALERT_WINDOW permission automatically, and
+ * then updated past api 23, and the app does not satisfy any of the other SAW permission flags,
+ * the permission should be revoked.
+ *
+ * @param newPackage The new package that was installed
+ * @param oldPackage The old package that was updated
+ */
+ private void revokeSystemAlertWindowIfUpgradedPast23(
+ @NonNull AndroidPackage newPackage,
+ @NonNull AndroidPackage oldPackage,
+ @NonNull PermissionCallback permissionCallback) {
+ if (oldPackage.getTargetSdkVersion() >= Build.VERSION_CODES.M
+ || newPackage.getTargetSdkVersion() < Build.VERSION_CODES.M
+ || !newPackage.getRequestedPermissions()
+ .contains(Manifest.permission.SYSTEM_ALERT_WINDOW)) {
+ return;
+ }
+
+ BasePermission saw;
+ synchronized (mLock) {
+ saw = mSettings.getPermissionLocked(Manifest.permission.SYSTEM_ALERT_WINDOW);
+ }
+ final PackageSetting ps = (PackageSetting)
+ mPackageManagerInt.getPackageSetting(newPackage.getPackageName());
+ if (grantSignaturePermission(Manifest.permission.SYSTEM_ALERT_WINDOW, newPackage, ps, saw,
+ ps.getPermissionsState())) {
+ return;
+ }
+ for (int userId : mUserManagerInt.getUserIds()) {
+ try {
+ revokePermissionFromPackageForUser(newPackage.getPackageName(),
+ Manifest.permission.SYSTEM_ALERT_WINDOW, false, userId, permissionCallback);
+ } catch (IllegalStateException | SecurityException e) {
+ Log.e(TAG, "unable to revoke SYSTEM_ALERT_WINDOW for "
+ + newPackage.getPackageName() + " user " + userId, e);
+ }
+ }
+ }
+
/**
* We might auto-grant permissions if any permission of the group is already granted. Hence if
* the group of a granted permission changes we need to revoke it to avoid having permissions of
@@ -4797,24 +4837,20 @@ public boolean isPermissionsReviewRequired(@NonNull AndroidPackage pkg,
return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId);
}
/**
- * If the app is updated, and has scoped storage permissions, then it is possible that the
- * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
+ * If the app is updated, then some checks need to be performed to ensure the
+ * package is not attempting to expoit permission changes across API boundaries.
* @param newPackage The new package that was installed
* @param oldPackage The old package that was updated
+ * @param allPackageNames The current packages in the system
*/
- public void revokeStoragePermissionsIfScopeExpanded(
- @NonNull AndroidPackage newPackage,
- @NonNull AndroidPackage oldPackage
- ) {
- PermissionManagerService.this.revokeStoragePermissionsIfScopeExpanded(newPackage,
- oldPackage, mDefaultPermissionCallback);
- }
-
- @Override
- public void revokeRuntimePermissionsIfGroupChanged(
+ public void onPackageUpdated(
@NonNull AndroidPackage newPackage,
@NonNull AndroidPackage oldPackage,
@NonNull ArrayList allPackageNames) {
+ PermissionManagerService.this.revokeStoragePermissionsIfScopeExpanded(newPackage,
+ oldPackage, mDefaultPermissionCallback);
+ PermissionManagerService.this.revokeSystemAlertWindowIfUpgradedPast23(newPackage,
+ oldPackage, mDefaultPermissionCallback);
PermissionManagerService.this.revokeRuntimePermissionsIfGroupChanged(newPackage,
oldPackage, allPackageNames, mDefaultPermissionCallback);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index df0edfa16924..7003c7a2027e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -239,16 +239,14 @@ public abstract void updatePermissions(@NonNull String packageName,
public abstract void resetRuntimePermissions(@NonNull AndroidPackage pkg,
@UserIdInt int userId);
- /**
- * We might auto-grant permissions if any permission of the group is already granted. Hence if
- * the group of a granted permission changes we need to revoke it to avoid having permissions of
- * the new group auto-granted.
- *
- * @param newPackage The new package that was installed
- * @param oldPackage The old package that was updated
- * @param allPackageNames All packages
- */
- public abstract void revokeRuntimePermissionsIfGroupChanged(
+ /**
+ * If the app is updated, then some checks need to be performed to ensure the package is not
+ * attempting to expoit permission changes across API boundaries.
+ * @param newPackage The new package that was installed
+ * @param oldPackage The old package that was updated
+ * @param allPackageNames The current packages in the system
+ */
+ public abstract void onPackageUpdated(
@NonNull AndroidPackage newPackage,
@NonNull AndroidPackage oldPackage,
@NonNull ArrayList allPackageNames);
@@ -265,17 +263,6 @@ public abstract void revokeRuntimePermissionsIfPermissionDefinitionChanged(
@NonNull List permissionsToRevoke,
@NonNull ArrayList allPackageNames);
- /**
- * If the app is updated, and has scoped storage permissions, then it is possible that the
- * app updated in an attempt to get unscoped storage. If so, revoke all storage permissions.
- * @param newPackage The new package that was installed
- * @param oldPackage The old package that was updated
- */
- public abstract void revokeStoragePermissionsIfScopeExpanded(
- @NonNull AndroidPackage newPackage,
- @NonNull AndroidPackage oldPackage
- );
-
/**
* Add all permissions in the given package.
*
From e2afd05b709576014439b7854b97eebb805ba90f Mon Sep 17 00:00:00 2001
From: Khoa Hong
Date: Fri, 23 Sep 2022 17:05:39 +0800
Subject: [PATCH 109/208] Add protections against queueing a UsbRequest when
the underlying UsbDeviceConnection is closed.
Bug: 204584366
Test: CTS Verifier: USB Accessory Test & USB Device Test
Test: No HWASan use-after-free reports with a test app
Change-Id: Ia3a9b10349efc0236b1539c81465f479cb32e02b
(cherry picked from commit 1691b54b1fda4239249a3871d2c17ed1ec753061)
Merged-In: Ia3a9b10349efc0236b1539c81465f479cb32e02b
---
.../hardware/usb/UsbDeviceConnection.java | 28 ++++++++
.../java/android/hardware/usb/UsbRequest.java | 68 ++++++++++++++++---
2 files changed, 86 insertions(+), 10 deletions(-)
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 53a5785f7c76..23f4c6301ec1 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -107,6 +107,34 @@ boolean isOpen() {
}
}
+ /**
+ * This is meant to be called by UsbRequest's queue() in order to synchronize on
+ * UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueRequest(UsbRequest request, ByteBuffer buffer, int length) {
+ synchronized (mLock) {
+ if (!isOpen()) {
+ return false;
+ }
+
+ return request.queueIfConnectionOpen(buffer, length);
+ }
+ }
+
+ /**
+ * This is meant to be called by UsbRequest's queue() in order to synchronize on
+ * UsbDeviceConnection's mLock to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueRequest(UsbRequest request, @Nullable ByteBuffer buffer) {
+ synchronized (mLock) {
+ if (!isOpen()) {
+ return false;
+ }
+
+ return request.queueIfConnectionOpen(buffer);
+ }
+ }
+
/**
* Releases all system resources related to the device.
* Once the object is closed it cannot be used again.
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 473df712e3f9..c5573214048c 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -113,11 +113,13 @@ public boolean initialize(UsbDeviceConnection connection, UsbEndpoint endpoint)
* Releases all resources related to this request.
*/
public void close() {
- if (mNativeContext != 0) {
- mEndpoint = null;
- mConnection = null;
- native_close();
- mCloseGuard.close();
+ synchronized (mLock) {
+ if (mNativeContext != 0) {
+ mEndpoint = null;
+ mConnection = null;
+ native_close();
+ mCloseGuard.close();
+ }
}
}
@@ -191,10 +193,32 @@ public void setClientData(Object data) {
*/
@Deprecated
public boolean queue(ByteBuffer buffer, int length) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new NullPointerException("invalid connection");
+ }
+
+ // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
+ // the connection being closed while queueing.
+ return connection.queueRequest(this, buffer, length);
+ }
+
+ /**
+ * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
+ * there, to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueIfConnectionOpen(ByteBuffer buffer, int length) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null || !connection.isOpen()) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new NullPointerException("invalid connection");
+ }
+
boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
boolean result;
- if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+ if (connection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
&& length > MAX_USBFS_BUFFER_SIZE) {
length = MAX_USBFS_BUFFER_SIZE;
}
@@ -243,6 +267,28 @@ public boolean queue(ByteBuffer buffer, int length) {
* @return true if the queueing operation succeeded
*/
public boolean queue(@Nullable ByteBuffer buffer) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new IllegalStateException("invalid connection");
+ }
+
+ // Calling into the underlying UsbDeviceConnection to synchronize on its lock, to prevent
+ // the connection being closed while queueing.
+ return connection.queueRequest(this, buffer);
+ }
+
+ /**
+ * This is meant to be called from UsbDeviceConnection after synchronizing using the lock over
+ * there, to prevent the connection being closed while queueing.
+ */
+ /* package */ boolean queueIfConnectionOpen(@Nullable ByteBuffer buffer) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null || !connection.isOpen()) {
+ // The expected exception by CTS Verifier - USB Device test
+ throw new IllegalStateException("invalid connection");
+ }
+
// Request need to be initialized
Preconditions.checkState(mNativeContext != 0, "request is not initialized");
@@ -260,7 +306,7 @@ public boolean queue(@Nullable ByteBuffer buffer) {
mIsUsingNewQueue = true;
wasQueued = native_queue(null, 0, 0);
} else {
- if (mConnection.getContext().getApplicationInfo().targetSdkVersion
+ if (connection.getContext().getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.P) {
// Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
@@ -363,11 +409,12 @@ public boolean queue(@Nullable ByteBuffer buffer) {
* @return true if cancelling succeeded
*/
public boolean cancel() {
- if (mConnection == null) {
+ UsbDeviceConnection connection = mConnection;
+ if (connection == null) {
return false;
}
- return mConnection.cancelRequest(this);
+ return connection.cancelRequest(this);
}
/**
@@ -382,7 +429,8 @@ public boolean cancel() {
* @return true if cancelling succeeded.
*/
/* package */ boolean cancelIfOpen() {
- if (mNativeContext == 0 || (mConnection != null && !mConnection.isOpen())) {
+ UsbDeviceConnection connection = mConnection;
+ if (mNativeContext == 0 || (connection != null && !connection.isOpen())) {
Log.w(TAG,
"Detected attempt to cancel a request on a connection which isn't open");
return false;
From d1a58f1eaf27fe6bec27b1693558d97e94aba83e Mon Sep 17 00:00:00 2001
From: Liahav Eitan
Date: Tue, 11 Oct 2022 13:20:52 +0000
Subject: [PATCH 110/208] Fix sharing to another profile where an app has
multiple targets
Moves the fixUris call from onTargetSelected directly to the intent
launch to ensure the intent which is actually started is updated with
userId specific URIs.
This is a backport of ag/19657256 and ag/20063949.
Bug:242165528
Bug:244876518
Bug:242605257
Test: manually share image from personal profile to work gmail,
first with chat target then backing up and selecting the main target
Test: manually share image from work Photos app to personal WhatsApp's
frequent contact target.
Change-Id: Id815984e691bf962e19e30a54f7247d16060b3b8
Merged-In: Id815984e691bf962e19e30a54f7247d16060b3b8
Merged-In: Ib41c8a3c46afcc2d62a4c1a924212bcd98bcfbe4
Merged-In: Iabf5dcf2612fe718f2f0886e2e5e9b76f37af1e1
(cherry picked from commit f50ced5f1e619d7fa7858748d6a9dbe861354f04)
Merged-In: Id815984e691bf962e19e30a54f7247d16060b3b8
---
.../com/android/internal/app/ResolverActivity.java | 12 ------------
.../internal/app/chooser/DisplayResolveInfo.java | 2 ++
.../internal/app/chooser/SelectableTargetInfo.java | 1 +
.../com/android/internal/app/chooser/TargetInfo.java | 11 +++++++++++
4 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index c5b84f7c9c83..998000c19cd0 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1233,9 +1233,6 @@ protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
}
if (target != null) {
- if (intent != null && isLaunchingTargetInOtherProfile()) {
- prepareIntentForCrossProfileLaunch(intent);
- }
safelyStartActivity(target);
// Rely on the ActivityManager to pop up a dialog regarding app suspension
@@ -1248,15 +1245,6 @@ protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
return true;
}
- private void prepareIntentForCrossProfileLaunch(Intent intent) {
- intent.fixUris(UserHandle.myUserId());
- }
-
- private boolean isLaunchingTargetInOtherProfile() {
- return mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
- != UserHandle.myUserId();
- }
-
@VisibleForTesting
public void safelyStartActivity(TargetInfo cti) {
// We're dispatching intents that might be coming from legacy apps, so
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index fe0e7d012262..cbbfbdd88a6c 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -178,6 +178,7 @@ public boolean startAsCaller(ResolverActivity activity, Bundle options, int user
if (ENABLE_CHOOSER_DELEGATE) {
return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
} else {
+ TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId);
return true;
}
@@ -185,6 +186,7 @@ public boolean startAsCaller(ResolverActivity activity, Bundle options, int user
@Override
public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+ TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
activity.startActivityAsUser(mResolvedIntent, options, user);
return false;
}
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 900e18d468bb..9d057b34363e 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -230,6 +230,7 @@ public boolean startAsCaller(ResolverActivity activity, Bundle options, int user
}
intent.setComponent(mChooserTarget.getComponentName());
intent.putExtras(mChooserTarget.getIntentExtras());
+ TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId);
// Important: we will ignore the target security checks in ActivityManager
// if and only if the ChooserTarget's target package is the same package
diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java
index f56ab17cb059..7bb7ddc65c6d 100644
--- a/core/java/com/android/internal/app/chooser/TargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/TargetInfo.java
@@ -130,4 +130,15 @@ public interface TargetInfo {
* @return true if this target should be pinned to the front by the request of the user
*/
boolean isPinned();
+
+ /**
+ * Fix the URIs in {@code intent} if cross-profile sharing is required. This should be called
+ * before launching the intent as another user.
+ */
+ static void prepareIntentForCrossProfileLaunch(Intent intent, int targetUserId) {
+ final int currentUserId = UserHandle.myUserId();
+ if (targetUserId != currentUserId) {
+ intent.fixUris(currentUserId);
+ }
+ }
}
From f404756c93cb7d436a0f74e377578e2c3fda675d Mon Sep 17 00:00:00 2001
From: Winson Chung
Date: Tue, 18 Oct 2022 05:21:30 +0000
Subject: [PATCH 111/208] Ensure that only SysUI can override pending intent
launch flags
- Originally added in ag/5139951, this method ensured that activities
launched from widgets are always started in a new task (if the
activity is launched in the home task, the task is not brough forward
with the recents transition). We can restrict this to only recents
callers since this only applies to 1p launchers in gesture nav
(both the gesture with 3p launchers and button nav in general will
always start the home intent directly, which makes adding the
NEW_TASK flag unnecessary).
Bug: 243794108
Test: Ensure that the original bug b/112508020 still works (with the
test app in the bug, swipe up still works after launching an
activity from the widget, and fails without applying the
override flags)
Change-Id: Id53c6a2aa6da5933d488ca06a0bfc4ef89a4c343
(cherry picked from commit c4d3106e347922610f8c554de3ae238175ed393e)
Merged-In: Id53c6a2aa6da5933d488ca06a0bfc4ef89a4c343
---
.../com/android/server/am/PendingIntentRecord.java | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 1997dbd6fc37..818b70d61d89 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -326,11 +326,16 @@ public int sendInner(int code, Intent intent, String resolvedType, IBinder white
resolvedType = key.requestResolvedType;
}
- // Apply any launch flags from the ActivityOptions. This is to ensure that the caller
- // can specify a consistent launch mode even if the PendingIntent is immutable
+ // Apply any launch flags from the ActivityOptions. This is used only by SystemUI
+ // to ensure that we can launch the pending intent with a consistent launch mode even
+ // if the provided PendingIntent is immutable (ie. to force an activity to launch into
+ // a new task, or to launch multiple instances if supported by the app)
final ActivityOptions opts = ActivityOptions.fromBundle(options);
if (opts != null) {
- finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+ // TODO(b/254490217): Move this check into SafeActivityOptions
+ if (controller.mAtmInternal.isCallerRecents(Binder.getCallingUid())) {
+ finalIntent.addFlags(opts.getPendingIntentLaunchFlags());
+ }
}
// Extract options before clearing calling identity
From ea419280cd0c0f6e0eea638380d7d7441dfba0fc Mon Sep 17 00:00:00 2001
From: Linus Tufvesson
Date: Thu, 28 Apr 2022 16:35:56 +0200
Subject: [PATCH 112/208] Make Activites touch opaque - DO NOT MERGE
Block touches from passing through activities by adding a dedicated
surface that consumes all touches that would otherwise pass through the
bounds availble to the Activity.
Bug: 194480991
Test: atest CtsWindowManagerDeviceTestCases:ActivityRecordInputSinkTests
Test: atest CtsWindowManagerDeviceTestCases:CrossAppDragAndDropTests
Test: atest CtsWindowManagerDeviceTestCases:PinnedStackTests
Test: Manually ran through go/wm-smoke (verified pip and splitscreen
still work)
Test: Manually verfied that freeform windows work and don't consume
touches outside their bounds
Change-Id: I01b35e34a63868dead4e728a3d359ae0942302f9
(cherry picked from commit 74ce78dfb4179cb317d6e2fc3cabe5f60af5d02d)
Merged-In: I01b35e34a63868dead4e728a3d359ae0942302f9
---
.../com/android/server/wm/ActivityRecord.java | 13 ++
.../server/wm/ActivityRecordInputSink.java | 113 ++++++++++++++++++
2 files changed, 126 insertions(+)
create mode 100644 services/core/java/com/android/server/wm/ActivityRecordInputSink.java
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 92dbfa4f1733..e5a069847f5c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -673,6 +673,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
private AppSaturationInfo mLastAppSaturationInfo;
+ private final ActivityRecordInputSink mActivityRecordInputSink;
+
+ // Activities with this uid are allowed to not create an input sink while being in the same
+ // task and directly above this ActivityRecord. This field is updated whenever a new activity
+ // is launched from this ActivityRecord. Touches are always allowed within the same uid.
+ int mAllowedTouchUid;
+
private final ColorDisplayService.ColorTransformController mColorTransformController =
(matrix, translation) -> mWmService.mH.post(() -> {
synchronized (mWmService.mGlobalLock) {
@@ -1650,6 +1657,8 @@ boolean isResolverOrChildActivity() {
? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
mHandoverLaunchDisplayId = options.getLaunchDisplayId();
}
+
+ mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
}
/**
@@ -3173,6 +3182,7 @@ private void cleanUpActivityServices() {
@Override
void removeImmediately() {
onRemovedFromDisplay();
+ mActivityRecordInputSink.releaseSurfaceControl();
super.removeImmediately();
}
@@ -6048,6 +6058,9 @@ void prepareSurfaces() {
} else if (!show && mLastSurfaceShowing) {
getSyncTransaction().hide(mSurfaceControl);
}
+ if (show) {
+ mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getSyncTransaction());
+ }
}
if (mThumbnail != null) {
mThumbnail.setShowing(getPendingTransaction(), show);
diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
new file mode 100644
index 000000000000..95b5cec9a144
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.os.Process;
+import android.view.InputWindowHandle;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+/**
+ * Creates a InputWindowHandle that catches all touches that would otherwise pass through an
+ * Activity.
+ */
+class ActivityRecordInputSink {
+
+ private final ActivityRecord mActivityRecord;
+ private final String mName;
+
+ private InputWindowHandle mInputWindowHandle;
+ private SurfaceControl mSurfaceControl;
+
+ ActivityRecordInputSink(ActivityRecord activityRecord, ActivityRecord sourceRecord) {
+ mActivityRecord = activityRecord;
+ mName = Integer.toHexString(System.identityHashCode(this)) + " ActivityRecordInputSink "
+ + mActivityRecord.mActivityComponent.flattenToShortString();
+ if (sourceRecord != null) {
+ sourceRecord.mAllowedTouchUid = mActivityRecord.getUid();
+ }
+ }
+
+ public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) {
+ boolean windowHandleChanged = updateInputWindowHandle();
+ if (mSurfaceControl == null) {
+ mSurfaceControl = createSurface(transaction);
+ }
+ if (windowHandleChanged) {
+ transaction.setInputWindowInfo(mSurfaceControl, mInputWindowHandle);
+ }
+ }
+
+ private SurfaceControl createSurface(SurfaceControl.Transaction t) {
+ SurfaceControl surfaceControl = mActivityRecord.makeChildSurface(null)
+ .setName(mName)
+ .setHidden(false)
+ .setCallsite("ActivityRecordInputSink.createSurface")
+ .build();
+ // Put layer below all siblings (and the parent surface too)
+ t.setLayer(surfaceControl, Integer.MIN_VALUE);
+ return surfaceControl;
+ }
+
+ private boolean updateInputWindowHandle() {
+ boolean changed = false;
+ if (mInputWindowHandle == null) {
+ mInputWindowHandle = createInputWindowHandle();
+ changed = true;
+ }
+ // Don't block touches from passing through to an activity below us in the same task, if
+ // that activity is either from the same uid or if that activity has launched an activity
+ // in our uid.
+ final ActivityRecord activityBelowInTask =
+ mActivityRecord.getTask().getActivityBelow(mActivityRecord);
+ final boolean allowPassthrough = activityBelowInTask != null && (
+ activityBelowInTask.mAllowedTouchUid == mActivityRecord.getUid()
+ || activityBelowInTask.isUid(mActivityRecord.getUid()));
+ boolean notTouchable = (mInputWindowHandle.layoutParamsFlags
+ & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0;
+ if (allowPassthrough || mActivityRecord.isAppTransitioning()) {
+ mInputWindowHandle.layoutParamsFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ changed |= !notTouchable;
+ } else {
+ mInputWindowHandle.layoutParamsFlags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ changed |= notTouchable;
+ }
+ return changed;
+ }
+
+ private InputWindowHandle createInputWindowHandle() {
+ InputWindowHandle inputWindowHandle = new InputWindowHandle(null,
+ mActivityRecord.getDisplayId());
+ inputWindowHandle.replaceTouchableRegionWithCrop = true;
+ inputWindowHandle.name = mName;
+ inputWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+ inputWindowHandle.ownerUid = Process.myUid();
+ inputWindowHandle.ownerPid = Process.myPid();
+ inputWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ inputWindowHandle.inputFeatures =
+ WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+ return inputWindowHandle;
+ }
+
+ void releaseSurfaceControl() {
+ if (mSurfaceControl != null) {
+ mSurfaceControl.release();
+ mSurfaceControl = null;
+ }
+ }
+
+}
From b631111b7532835059690922762605fddaab8403 Mon Sep 17 00:00:00 2001
From: Jackal Guo
Date: Tue, 25 Oct 2022 15:01:33 +0800
Subject: [PATCH 113/208] [RESTRICT AUTOMERGE] Correct the behavior of
ACTION_PACKAGE_DATA_CLEARED
This action should be only broadcasted when the user data is cleared
successfully. Broadcasting this action when failed case may result in
unexpected result.
Bug: 240267890
Test: manually using the PoC in the buganizer to ensure the symptom
no longer exists.
Change-Id: I53b67eb0a200f9dfb6fa2559227b7c735f30624f
(cherry picked from commit 0587cd294ae958af5ce7dd505fa919b4e3a13a6a)
Merged-In: I53b67eb0a200f9dfb6fa2559227b7c735f30624f
---
.../server/am/ActivityManagerService.java | 32 +++++++++++--------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a8d981e2f64c..0054a8f8d033 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4288,20 +4288,24 @@ public void onRemoveCompleted(String packageName, boolean succeeded)
finishForceStopPackageLocked(packageName, appInfo.uid);
}
}
- final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
- Uri.fromParts("package", packageName, null));
- intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- intent.putExtra(Intent.EXTRA_UID, (appInfo != null) ? appInfo.uid : -1);
- intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
- if (isInstantApp) {
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
- null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null,
- false, false, resolvedUserId, false);
- } else {
- broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
- null, null, 0, null, null, null, null, false, false, resolvedUserId,
- false);
+
+ if (succeeded) {
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
+ Uri.fromParts("package", packageName, null /* fragment */));
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ intent.putExtra(Intent.EXTRA_UID,
+ (appInfo != null) ? appInfo.uid : Process.INVALID_UID);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, resolvedUserId);
+ if (isInstantApp) {
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ }
+
+ broadcastIntentInPackage("android", null /* featureId */, SYSTEM_UID,
+ uid, pid, intent, null /* resolvedType */, null /* resultTo */,
+ 0 /* resultCode */, null /* resultData */, null /* resultExtras */,
+ isInstantApp ? permission.ACCESS_INSTANT_APPS : null,
+ null /* bOptions */, false /* serialized */, false /* sticky */,
+ resolvedUserId, false /* allowBackgroundActivityStarts */);
}
if (observer != null) {
From 8c22f850afe26a3443050e716900d243692b017f Mon Sep 17 00:00:00 2001
From: Dmitry Dementyev
Date: Tue, 22 Nov 2022 22:54:01 +0000
Subject: [PATCH 114/208] Convert argument to intent in
ChooseTypeAndAccountActivity
Bug: 244154558
Test: manual
Change-Id: I5a86639cd571e14e9a9f5d5ded631b5a7c08db7e
(cherry picked from commit ede0a767c26f144e38b4a0c1c2f530b05ffd29a8)
Merged-In: I5a86639cd571e14e9a9f5d5ded631b5a7c08db7e
---
core/java/android/accounts/ChooseTypeAndAccountActivity.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 8cdc6a71caf8..adfe171f1a8d 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -407,7 +407,7 @@ public void run(final AccountManagerFuture accountManagerFuture) {
mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
mCallingUid);
intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
+ startActivityForResult(new Intent(intent), REQUEST_ADD_ACCOUNT);
return;
}
} catch (OperationCanceledException e) {
From 01af156bc66876eafc52b0a71d26904f74ac2d8c Mon Sep 17 00:00:00 2001
From: Yuri Lin
Date: Wed, 9 Nov 2022 15:26:20 -0500
Subject: [PATCH 115/208] Use rule package name in addAutomaticZenRule; specify
"android" for all system apps
This is a roll forward of two reverted changes combined into one:
commit b6d04416628ab29df57efcd738332912d9260cea
commit e5e51116fb767162966a8e0d23fafb4f0ff46e86
It additionally fixes an issue where in multi-user profiles (such as a guest user), rules would be incorrectly identified as not created by the system and would therefore fail to be created in settings.
Bug: 257477671
Bug: 245236706
Bug: 242537431
Test: NotificationManagerServiceTest; ZenModeHelperTest; manually verified that it's possible to create zen schedules from guest mode
Change-Id: I0c4c705cfe5fc875151958957daaf8657fbc21a7
Merged-In: I0c4c705cfe5fc875151958957daaf8657fbc21a7
(cherry picked from commit 7261cdd30bf18965d421fc28c68c61e380bc952d)
(cherry picked from commit 7e58ab94f9e3b2f65ae18d515a81c1a31fd4dde6)
Merged-In: I0c4c705cfe5fc875151958957daaf8657fbc21a7
---
.../NotificationManagerService.java | 17 +++-
.../server/notification/ZenModeHelper.java | 7 +-
.../NotificationManagerServiceTest.java | 66 ++++++++++++++
.../notification/ZenModeHelperTest.java | 90 +++++++++++++++++++
4 files changed, 173 insertions(+), 7 deletions(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 60d7ec51ca09..f6ead70b446d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4523,7 +4523,16 @@ public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg)
}
enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
- return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
+ // If the calling app is the system (from any user), take the package name from the
+ // rule's owner rather than from the caller's package.
+ String rulePkg = pkg;
+ if (isCallingAppIdSystem()) {
+ if (automaticZenRule.getOwner() != null) {
+ rulePkg = automaticZenRule.getOwner().getPackageName();
+ }
+ }
+
+ return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
"addAutomaticZenRule");
}
@@ -8731,6 +8740,12 @@ protected boolean isCallingUidSystem() {
return uid == Process.SYSTEM_UID;
}
+ protected boolean isCallingAppIdSystem() {
+ final int uid = Binder.getCallingUid();
+ final int appid = UserHandle.getAppId(uid);
+ return appid == Process.SYSTEM_UID;
+ }
+
protected boolean isUidSystemOrPhone(int uid) {
final int appid = UserHandle.getAppId(uid);
return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 1c55762f132d..c96aac6e9914 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -305,7 +305,7 @@ public AutomaticZenRule getAutomaticZenRule(String id) {
public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
String reason) {
- if (!isSystemRule(automaticZenRule)) {
+ if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
if (component == null) {
component = getActivityInfo(automaticZenRule.getConfigurationActivity());
@@ -554,11 +554,6 @@ protected void updateDefaultZenRules() {
}
}
- private boolean isSystemRule(AutomaticZenRule rule) {
- return rule.getOwner() != null
- && ZenModeConfig.SYSTEM_AUTHORITY.equals(rule.getOwner().getPackageName());
- }
-
private ServiceInfo getServiceInfo(ComponentName owner) {
Intent queryIntent = new Intent();
queryIntent.setComponent(owner);
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 2239769a3525..6a8815faa9e6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -308,6 +308,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private static class TestableNotificationManagerService extends NotificationManagerService {
int countSystemChecks = 0;
boolean isSystemUid = true;
+ boolean isSystemAppId = true;
int countLogSmartSuggestionsVisible = 0;
// If true, don't enqueue the PostNotificationRunnables, just trap them
boolean trapEnqueuedNotifications = false;
@@ -334,6 +335,12 @@ protected boolean isCallingUidSystem() {
return isSystemUid;
}
+ @Override
+ protected boolean isCallingAppIdSystem() {
+ countSystemChecks++;
+ return isSystemUid || isSystemAppId;
+ }
+
@Override
protected boolean isCallerSystemOrPhone() {
countSystemChecks++;
@@ -5936,6 +5943,65 @@ public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Except
mBinderService.addAutomaticZenRule(rule, mContext.getPackageName());
}
+ @Test
+ public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
+ mService.isSystemUid = true;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "com.android.settings");
+
+ // verify that zen mode helper gets passed in a package name of "android"
+ verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception {
+ // The multi-user case: where the calling uid doesn't match the system uid, but the calling
+ // *appid* is the system.
+ mService.isSystemUid = false;
+ mService.isSystemAppId = true;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "com.android.settings");
+
+ // verify that zen mode helper gets passed in a package name of "android"
+ verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
+ mService.isSystemUid = false;
+ mService.isSystemAppId = false;
+ ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+ when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+ .thenReturn(true);
+ mService.setZenHelper(mockZenModeHelper);
+ ComponentName owner = new ComponentName("android", "ProviderName");
+ ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+ boolean isEnabled = true;
+ AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+ zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+ mBinderService.addAutomaticZenRule(rule, "another.package");
+
+ // verify that zen mode helper gets passed in the package name from the arg, not the owner
+ verify(mockZenModeHelper).addAutomaticZenRule(
+ eq("another.package"), eq(rule), anyString());
+ }
+
@Test
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
try {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index fcf4d88f7c90..1a1e3ddd968e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1575,6 +1575,96 @@ public void testAddAutomaticZenRule() {
assertEquals(zenRule.getName(), ruleInConfig.name);
}
+ @Test
+ public void testAddAutomaticZenRule_beyondSystemLimit() {
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ // We need the package name to be something that's not "android" so there aren't any
+ // existing rules under that package.
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProvider"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_beyondSystemLimit_differentComponents() {
+ // Make sure the system limit is enforced per-package even with different component provider
+ // names.
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ null,
+ new ComponentName("android", "ScheduleConditionProvider" + i),
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ null,
+ new ComponentName("android", "ScheduleConditionProviderFinal"),
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+ }
+
+ @Test
+ public void testAddAutomaticZenRule_claimedSystemOwner() {
+ // Make sure anything that claims to have a "system" owner but not actually part of the
+ // system package still gets limited on number of rules
+ for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) {
+ ScheduleInfo si = new ScheduleInfo();
+ si.startHour = i;
+ AutomaticZenRule zenRule = new AutomaticZenRule("name" + i,
+ new ComponentName("android", "ScheduleConditionProvider" + i),
+ null, // configuration activity
+ ZenModeConfig.toScheduleConditionId(si),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ assertNotNull(id);
+ }
+ try {
+ AutomaticZenRule zenRule = new AutomaticZenRule("name",
+ new ComponentName("android", "ScheduleConditionProviderFinal"),
+ null, // configuration activity
+ ZenModeConfig.toScheduleConditionId(new ScheduleInfo()),
+ new ZenPolicy.Builder().build(),
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test");
+ fail("allowed too many rules to be created");
+ } catch (IllegalArgumentException e) {
+ // yay
+ }
+ }
+
private void setupZenConfig() {
mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
mZenModeHelperSpy.mConfig.allowAlarms = false;
From 536a81886b6d3f1cef684c120918a5439c242ca1 Mon Sep 17 00:00:00 2001
From: Louis Chang
Date: Wed, 4 Jan 2023 05:00:37 +0000
Subject: [PATCH 116/208] Revert "[RESTRICT AUTOMERGE] Trim the activity info
of another uid if no privilege"
This reverts commit 17df433a3d96fb6c00dc7078fd0f8048645ace6a.
Reason for revert: apps crashed due to the top activity info trimmed
Bug: 264269392 263434196 263438172
Change-Id: I078080b14b7cf7c6e605739f22f40f86802d3950
(cherry picked from commit 5caf2dde3d264966e1ba0dd3e18a0524858157ba)
Merged-In: I078080b14b7cf7c6e605739f22f40f86802d3950
---
.../com/android/server/wm/AppTaskImpl.java | 2 +-
.../com/android/server/wm/RecentTasks.java | 8 ++-----
.../com/android/server/wm/RunningTasks.java | 4 ----
.../core/java/com/android/server/wm/Task.java | 21 -------------------
4 files changed, 3 insertions(+), 32 deletions(-)
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 2fd5963d653b..dd1d55b2d54d 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -84,7 +84,7 @@ public ActivityManager.RecentTaskInfo getTaskInfo() {
throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
}
return mService.getRecentTasks().createRecentTaskInfo(task,
- false /* stripExtras */, true /* getTasksAllowed */);
+ false /* stripExtras */);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 6151b1892fda..3fe75a4ab49e 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -962,7 +962,7 @@ private ArrayList getRecentTasksImpl(int maxNum,
continue;
}
- res.add(createRecentTaskInfo(task, true /* stripExtras */, getTasksAllowed));
+ res.add(createRecentTaskInfo(task, true /* stripExtras */));
}
return res;
}
@@ -1834,16 +1834,12 @@ void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
/**
* Creates a new RecentTaskInfo from a Task.
*/
- ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras,
- boolean getTasksAllowed) {
+ ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
tr.fillTaskInfo(rti, stripExtras);
// Fill in some deprecated values
rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
rti.persistentId = rti.taskId;
- if (!getTasksAllowed) {
- Task.trimIneffectiveInfo(tr, rti);
- }
return rti;
}
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 3c7917bb05d1..3509ba72d058 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -129,10 +129,6 @@ private RunningTaskInfo createRunningTaskInfo(Task task) {
final RunningTaskInfo rti = task.getTaskInfo();
// Fill in some deprecated values
rti.id = rti.taskId;
-
- if (!mAllowed) {
- Task.trimIneffectiveInfo(task, rti);
- }
return rti;
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c0e4262863e6..228b5054c13f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3653,27 +3653,6 @@ void fillTaskInfo(TaskInfo info, boolean stripExtras) {
: SCREEN_ORIENTATION_UNSET;
}
- /**
- * Removes the activity info if the activity belongs to a different uid, which is
- * different from the app that hosts the task.
- */
- static void trimIneffectiveInfo(Task task, TaskInfo info) {
- final ActivityRecord baseActivity = task.getActivity(r -> !r.finishing,
- false /* traverseTopToBottom */);
- final int baseActivityUid =
- baseActivity != null ? baseActivity.getUid() : task.effectiveUid;
-
- if (info.topActivityInfo != null
- && task.effectiveUid != info.topActivityInfo.applicationInfo.uid) {
- info.topActivity = null;
- info.topActivityInfo = null;
- }
-
- if (task.effectiveUid != baseActivityUid) {
- info.baseActivity = null;
- }
- }
-
/**
* Returns a {@link TaskInfo} with information from this task.
*/
From bfc32efc49a307dfa44d7dbc4e383097075246e0 Mon Sep 17 00:00:00 2001
From: Julia Reynolds
Date: Mon, 16 May 2022 15:28:24 -0400
Subject: [PATCH 117/208] Move service initialization
Occasionally ILockSettings can fail to be initialized otherwise
Fixes: 232714129
Test: boot (and eventually bootstress/reboot-long)
Change-Id: I2f9f9bdba37f4ebfaea56c1a6662f0474ae8a002
Merged-In: I2f9f9bdba37f4ebfaea56c1a6662f0474ae8a002
(cherry picked from commit 8e278543bd290d4b6c417758554d6dee93a4fe74)
(cherry picked from commit caa5a22ea0c401c4eef548fb8161820beda3ff13)
Merged-In: I2f9f9bdba37f4ebfaea56c1a6662f0474ae8a002
---
.../server/notification/NotificationManagerService.java | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f6ead70b446d..346d586bab38 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1776,7 +1776,6 @@ public synchronized void onStrongAuthRequiredChanged(int userId) {
}
}
- private LockPatternUtils mLockPatternUtils;
private StrongAuthTracker mStrongAuthTracker;
public NotificationManagerService(Context context) {
@@ -1996,7 +1995,6 @@ void init(WorkerHandler handler, RankingHandler rankingHandler,
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
mUiHandler = new Handler(UiThread.get().getLooper());
- mLockPatternUtils = new LockPatternUtils(getContext());
mStrongAuthTracker = new StrongAuthTracker(getContext());
String[] extractorNames;
try {
@@ -2445,7 +2443,7 @@ public void onBootPhase(int phase) {
bubbsExtractor.setShortcutHelper(mShortcutHelper);
}
registerNotificationPreferencesPullers();
- mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
+ new LockPatternUtils(getContext()).registerStrongAuthTracker(mStrongAuthTracker);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
From 4b17f4d01b89acf82d6ec206728125d3e5e0909a Mon Sep 17 00:00:00 2001
From: Alex Johnston
Date: Tue, 5 Oct 2021 11:44:37 +0000
Subject: [PATCH 118/208] Stop managed profile owner granting READ_SMS
Reason: There is only one telephony stack shared
between the personal and work profile.
Bug: 194382185
Bug: 189942529
Test: build
Change-Id: If0d27a317a7c0ee46af371b30208327e5636c7cf
(cherry picked from commit 87f37319bf7ee22c6e7c29432b6c9bbce0fdb591)
Merged-In: If0d27a317a7c0ee46af371b30208327e5636c7cf
---
core/java/android/app/admin/DevicePolicyManager.java | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c2f00215dd3d..aa6d74fb8c39 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9661,6 +9661,15 @@ public int getPermissionPolicy(ComponentName admin) {
* {@link android.os.Build.VERSION_CODES#M} the app-op matching the permission is set to
* {@link android.app.AppOpsManager#MODE_IGNORED}, but the permission stays granted.
*
+ * Control over the following permissions are restricted for managed profile owners:
+ *
+ * - Manifest.permission.READ_SMS
+ *
+ *
+ * A managed profile owner may not grant these permissions (i.e. call this method with any of
+ * the permissions listed above and {@code grantState} of
+ * {@code #PERMISSION_GRANT_STATE_GRANTED}), but may deny them.
+ *
* @param admin Which profile or device owner this request is associated with.
* @param packageName The application to grant or revoke a permission to.
* @param permission The permission to grant or revoke.
From 6cee00a9d81cfcf1e7d27bbb9238d504a8f06a7e Mon Sep 17 00:00:00 2001
From: Wenhao Wang
Date: Tue, 30 Aug 2022 11:09:46 -0700
Subject: [PATCH 119/208] Enable user graularity for lockdown mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The NotificationManagerService registers a LockPatternUtils.StrongAuthTracker
to observe the StrongAuth changes of every user.
More specifically, it’s the STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN flag.
Via this flag, NotificationManagerService can perform the following operations
when the user enter or exit lockdown mode:
Enter lockdown:
1. Remove all the notifications belonging to the user.
2. Set the local flag to indicate the lockdown is on for the user.
The local flag will suppress the user's notifications on the
post, remove and update functions.
Exit lockdown:
1. Clear the local flag to indicate the lockdown is off for the user.
2. Repost the user’s notifications (suppressed during lockdown mode).
The CL also updates corresponding tests.
Bug: 173721373
Bug: 250743174
Test: atest NotificationManagerServiceTest
Test: atest NotificationListenersTest
Ignore-AOSP-First: pending fix for a security issue.
Change-Id: I4f30e56550729db7d673a92d2a1250509713f36d
Merged-In: I4f30e56550729db7d673a92d2a1250509713f36d
(cherry picked from commit de3b12fca23178d8c821058261572449b67d5967)
(cherry picked from commit 5e40f39f5bd4ae769d79ce022a64f1345512b65d)
Merged-In: I4f30e56550729db7d673a92d2a1250509713f36d
---
.../NotificationManagerService.java | 75 +++++----
.../NotificationListenersTest.java | 150 ++++++++++++------
.../NotificationManagerServiceTest.java | 72 ++++++++-
3 files changed, 209 insertions(+), 88 deletions(-)
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 346d586bab38..14454596db3d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1744,34 +1744,39 @@ private boolean containsFlag(int haystack, int needle) {
return (haystack & needle) != 0;
}
- public boolean isInLockDownMode() {
- return mIsInLockDownMode;
+ // Return whether the user is in lockdown mode.
+ // If the flag is not set, we assume the user is not in lockdown.
+ public boolean isInLockDownMode(int userId) {
+ return mUserInLockDownMode.get(userId, false);
}
@Override
public synchronized void onStrongAuthRequiredChanged(int userId) {
boolean userInLockDownModeNext = containsFlag(getStrongAuthForUser(userId),
STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
- mUserInLockDownMode.put(userId, userInLockDownModeNext);
- boolean isInLockDownModeNext = mUserInLockDownMode.indexOfValue(true) != -1;
- if (mIsInLockDownMode == isInLockDownModeNext) {
+ // Nothing happens if the lockdown mode of userId keeps the same.
+ if (userInLockDownModeNext == isInLockDownMode(userId)) {
return;
}
- if (isInLockDownModeNext) {
- cancelNotificationsWhenEnterLockDownMode();
+ // When the lockdown mode is changed, we perform the following steps.
+ // If the userInLockDownModeNext is true, all the function calls to
+ // notifyPostedLocked and notifyRemovedLocked will not be executed.
+ // The cancelNotificationsWhenEnterLockDownMode calls notifyRemovedLocked
+ // and postNotificationsWhenExitLockDownMode calls notifyPostedLocked.
+ // So we shall call cancelNotificationsWhenEnterLockDownMode before
+ // we set mUserInLockDownMode as true.
+ // On the other hand, if the userInLockDownModeNext is false, we shall call
+ // postNotificationsWhenExitLockDownMode after we put false into mUserInLockDownMode
+ if (userInLockDownModeNext) {
+ cancelNotificationsWhenEnterLockDownMode(userId);
}
- // When the mIsInLockDownMode is true, both notifyPostedLocked and
- // notifyRemovedLocked will be dismissed. So we shall call
- // cancelNotificationsWhenEnterLockDownMode before we set mIsInLockDownMode
- // as true and call postNotificationsWhenExitLockDownMode after we set
- // mIsInLockDownMode as false.
- mIsInLockDownMode = isInLockDownModeNext;
+ mUserInLockDownMode.put(userId, userInLockDownModeNext);
- if (!isInLockDownModeNext) {
- postNotificationsWhenExitLockDownMode();
+ if (!userInLockDownModeNext) {
+ postNotificationsWhenExitLockDownMode(userId);
}
}
}
@@ -8704,11 +8709,14 @@ protected void unhideNotificationsForPackages(String[] pkgs) {
}
}
- private void cancelNotificationsWhenEnterLockDownMode() {
+ private void cancelNotificationsWhenEnterLockDownMode(int userId) {
synchronized (mNotificationLock) {
int numNotifications = mNotificationList.size();
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
+ if (rec.getUser().getIdentifier() != userId) {
+ continue;
+ }
mListeners.notifyRemovedLocked(rec, REASON_CANCEL_ALL,
rec.getStats());
}
@@ -8716,14 +8724,23 @@ private void cancelNotificationsWhenEnterLockDownMode() {
}
}
- private void postNotificationsWhenExitLockDownMode() {
+ private void postNotificationsWhenExitLockDownMode(int userId) {
synchronized (mNotificationLock) {
int numNotifications = mNotificationList.size();
+ // Set the delay to spread out the burst of notifications.
+ long delay = 0;
for (int i = 0; i < numNotifications; i++) {
NotificationRecord rec = mNotificationList.get(i);
- mListeners.notifyPostedLocked(rec, rec);
+ if (rec.getUser().getIdentifier() != userId) {
+ continue;
+ }
+ mHandler.postDelayed(() -> {
+ synchronized (mNotificationLock) {
+ mListeners.notifyPostedLocked(rec, rec);
+ }
+ }, delay);
+ delay += 20;
}
-
}
}
@@ -8930,12 +8947,15 @@ private static String callStateToString(int state) {
* notifications visible to the given listener.
*/
@GuardedBy("mNotificationLock")
- private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
+ NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
final int N = mNotificationList.size();
final ArrayList rankings = new ArrayList<>();
for (int i = 0; i < N; i++) {
NotificationRecord record = mNotificationList.get(i);
+ if (isInLockDownMode(record.getUser().getIdentifier())) {
+ continue;
+ }
if (!isVisibleToListener(record.getSbn(), info)) {
continue;
}
@@ -8974,8 +8994,8 @@ private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo inf
rankings.toArray(new NotificationListenerService.Ranking[0]));
}
- boolean isInLockDownMode() {
- return mStrongAuthTracker.isInLockDownMode();
+ boolean isInLockDownMode(int userId) {
+ return mStrongAuthTracker.isInLockDownMode(userId);
}
boolean hasCompanionDevice(ManagedServiceInfo info) {
@@ -9010,7 +9030,8 @@ protected ICompanionDeviceManager getCompanionManager() {
ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
}
- private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
+ @VisibleForTesting
+ boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
if (!listener.enabledAndUserMatches(sbn.getUserId())) {
return false;
}
@@ -9696,7 +9717,7 @@ public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
@GuardedBy("mNotificationLock")
void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
boolean notifyAllListeners) {
- if (isInLockDownMode()) {
+ if (isInLockDownMode(r.getUser().getIdentifier())) {
return;
}
@@ -9796,7 +9817,7 @@ private void updateUriPermissionsForActiveNotificationsLocked(
@GuardedBy("mNotificationLock")
public void notifyRemovedLocked(NotificationRecord r, int reason,
NotificationStats notificationStats) {
- if (isInLockDownMode()) {
+ if (isInLockDownMode(r.getUser().getIdentifier())) {
return;
}
@@ -9845,10 +9866,6 @@ public void notifyRemovedLocked(NotificationRecord r, int reason,
*/
@GuardedBy("mNotificationLock")
public void notifyRankingUpdateLocked(List