From c0ac625e276b11ccd5bc1fd83a8f30f0c0ff761b Mon Sep 17 00:00:00 2001 From: Songchun Fan Date: Thu, 26 Jan 2023 17:43:24 -0800 Subject: [RESTRICT AUTOMERGE][pm] prevent system app downgrades of versions lower than preload Also remove misleading commandline output. BUG: 256202273 Test: manual 1. Install preload system app v90, reboot 2. (W/O data, W/ Flag, 90->80 NOK) adb install -d ~/Downloads/PrivApplication_80.apk Performing Streamed Install adb: failed to install /usr/local/google/home/schfan/Downloads/PrivApplication_80.apk: Failure [INSTALL_FAILED_VERSION_DOWNGRADE: System app: com.example.privapplication cannot be downgraded to older than its preloaded version on the system image. Update version code 80 is older than current 90] 3. (90->100) Install data app v100 4. (W/ data, W/O Flag, 100->90 NOK) adb install ~/Downloads/PrivApplication_90.apk Performing Streamed Install adb: failed to install /usr/local/google/home/schfan/Downloads/PrivApplication_90.apk: Failure [INSTALL_FAILED_VERSION_DOWNGRADE: Downgrade detected: Update version code 90 is older than current 100] 5. (W/ data, W/ Flag, 100->90 downgrade OK) adb install -d ~/Downloads/PrivApplication_90.apk Performing Streamed Install Success 6. (90->100) Install v100 6. (W/data, W/ Flag, 100->80 NOK) adb install -d ~/Downloads/PrivApplication_80.apk Performing Streamed Install adb: failed to install /usr/local/google/home/schfan/Downloads/PrivApplication_80.apk: Failure [INSTALL_FAILED_VERSION_DOWNGRADE: System app: com.example.privapplication cannot be downgraded to older than its preloaded version on the system image. Update version code 80 is older than current 90] Change-Id: I5a8ee9e29a3a58f6e3fd188e0122355744b8b0ce (cherry picked from commit a4484d7f1be1fa413258fe18644d61f85611f586) (cherry picked from commit on googleplex-android-review.googlesource.com host: d7c72817477b7b76ea41a55067057872d5b434bf) Merged-In: I5a8ee9e29a3a58f6e3fd188e0122355744b8b0ce --- .../android/server/pm/InstallPackageHelper.java | 25 +++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 64a9a563e4a2..ae62f4107591 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -2429,10 +2429,10 @@ final class InstallPackageHelper { // will be null whereas dataOwnerPkg will contain information about the package // which was uninstalled while keeping its data. AndroidPackage dataOwnerPkg = mPm.mPackages.get(packageName); + PackageSetting dataOwnerPs = mPm.mSettings.getPackageLPr(packageName); if (dataOwnerPkg == null) { - PackageSetting ps = mPm.mSettings.getPackageLPr(packageName); - if (ps != null) { - dataOwnerPkg = ps.getPkg(); + if (dataOwnerPs != null) { + dataOwnerPkg = dataOwnerPs.getPkg(); } } @@ -2460,6 +2460,7 @@ final class InstallPackageHelper { if (dataOwnerPkg != null && !dataOwnerPkg.isSdkLibrary()) { if (!PackageManagerServiceUtils.isDowngradePermitted(installFlags, dataOwnerPkg.isDebuggable())) { + // Downgrade is not permitted; a lower version of the app will not be allowed try { PackageManagerServiceUtils.checkDowngrade(dataOwnerPkg, pkgLite); } catch (PackageManagerException e) { @@ -2468,6 +2469,24 @@ final class InstallPackageHelper { return Pair.create( PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg); } + } else if (dataOwnerPs.isSystem()) { + // Downgrade is permitted, but system apps can't be downgraded below + // the version preloaded onto the system image + final PackageSetting disabledPs = mPm.mSettings.getDisabledSystemPkgLPr( + dataOwnerPs); + if (disabledPs != null) { + dataOwnerPkg = disabledPs.getPkg(); + } + try { + PackageManagerServiceUtils.checkDowngrade(dataOwnerPkg, pkgLite); + } catch (PackageManagerException e) { + String errorMsg = "System app: " + packageName + " cannot be downgraded to" + + " older than its preloaded version on the system image. " + + e.getMessage(); + Slog.w(TAG, errorMsg); + return Pair.create( + PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg); + } } } } -- cgit v1.2.3 From 1b04c3b8aa7a866feae7eb44ab92cc80e03c9c22 Mon Sep 17 00:00:00 2001 From: Songchun Fan Date: Thu, 2 Feb 2023 10:35:56 -0800 Subject: [RESTRICT AUTOMERGE][pm] still allow debuggable for system app downgrades Turns out we do have internal tests that downgrades system apps, so adding this exception to allow for that. BUG: 267232653 BUG: 256202273 Test: manual Change-Id: Ie281bbdc8788ee64ff99a7c5150da7ce7926235e (cherry picked from commit ceeca68b8c3f0ed8427b0212f63defe2f075146e) (cherry picked from commit on googleplex-android-review.googlesource.com host: 3a04799f68de6b77fc89faddda032b1031551e78) Merged-In: Ie281bbdc8788ee64ff99a7c5150da7ce7926235e --- .../android/server/pm/InstallPackageHelper.java | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index ae62f4107591..c32a57c68ede 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -2477,15 +2477,19 @@ final class InstallPackageHelper { if (disabledPs != null) { dataOwnerPkg = disabledPs.getPkg(); } - try { - PackageManagerServiceUtils.checkDowngrade(dataOwnerPkg, pkgLite); - } catch (PackageManagerException e) { - String errorMsg = "System app: " + packageName + " cannot be downgraded to" - + " older than its preloaded version on the system image. " - + e.getMessage(); - Slog.w(TAG, errorMsg); - return Pair.create( - PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg); + if (!Build.IS_DEBUGGABLE && !dataOwnerPkg.isDebuggable()) { + // Only restrict non-debuggable builds and non-debuggable version of the app + try { + PackageManagerServiceUtils.checkDowngrade(dataOwnerPkg, pkgLite); + } catch (PackageManagerException e) { + String errorMsg = + "System app: " + packageName + " cannot be downgraded to" + + " older than its preloaded version on the system" + + " image. " + e.getMessage(); + Slog.w(TAG, errorMsg); + return Pair.create( + PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE, errorMsg); + } } } } -- cgit v1.2.3 From f0af195296dec9170cec1787240605f5d5768e69 Mon Sep 17 00:00:00 2001 From: Chris Li Date: Mon, 13 Feb 2023 14:56:14 +0800 Subject: Re-enforce MANAGE_ACTIVITY_TASKS for applySyncTransaction The conditional permission was introduced for TaskFragmentOrganizer, but not really needed. Remove the conditional check. Bug: 259938771 Test: pass existing tests Merged-In: I666b9ee6b6076766513b97e675fdbaa002428601 Change-Id: I666b9ee6b6076766513b97e675fdbaa002428601 (cherry picked from commit on googleplex-android-review.googlesource.com host: 65ac64c3476f42f8437481bff77485f53ab4f391) Merged-In: I666b9ee6b6076766513b97e675fdbaa002428601 --- core/api/test-current.txt | 2 +- core/java/android/window/WindowOrganizer.java | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 70a23cdf106b..650d51ce39f5 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3452,7 +3452,7 @@ package android.window { public class WindowOrganizer { ctor public WindowOrganizer(); - method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); + method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull android.window.WindowContainerTransaction, @NonNull android.window.WindowContainerTransactionCallback); method @RequiresPermission(value=android.Manifest.permission.MANAGE_ACTIVITY_TASKS, conditional=true) public void applyTransaction(@NonNull android.window.WindowContainerTransaction); } diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java index 2a80d021abd6..740fbacbbfcc 100644 --- a/core/java/android/window/WindowOrganizer.java +++ b/core/java/android/window/WindowOrganizer.java @@ -61,9 +61,7 @@ public class WindowOrganizer { * Apply multiple WindowContainer operations at once. * * Note that using this API requires the caller to hold - * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}, unless the caller is using - * {@link TaskFragmentOrganizer}, in which case it is allowed to change TaskFragment that is - * created by itself. + * {@link android.Manifest.permission#MANAGE_ACTIVITY_TASKS}. * * @param t The transaction to apply. * @param callback This transaction will use the synchronization scheme described in @@ -72,8 +70,7 @@ public class WindowOrganizer { * @return An ID for the sync operation which will later be passed to transactionReady callback. * This lets the caller differentiate overlapping sync operations. */ - @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS, - conditional = true) + @RequiresPermission(value = android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public int applySyncTransaction(@NonNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback) { try { -- cgit v1.2.3 From 05f193365428996acec0633ebf088987325d764b Mon Sep 17 00:00:00 2001 From: Issei Suzuki Date: Fri, 10 Feb 2023 17:10:28 +0000 Subject: FIx occlusion status mismatch issue when screen turns off and on quickly When KeyguardController detects occlude status change while the keyguard is shown, it requests (UN)OCCLUDE app transition and PhoneWindowManager defers committing the occlude state. However KeyguardController and PhoneWindowManager use different predicates to decide if keygaurd is shown or not. In case the predicates return different value, occlude state in KeyguardController and PhoneWindowManager remain inconsistent. Test: manual 1. set secure lock method (pattern) 2. launch calculator app 3. push power button to screen off 4. just before the screen turns off, push power button to screen on again Bug: 232002936 Change-Id: I4cd7e62e6800897cce50a5376495c499a0b9ad10 (cherry picked from commit b71c7b40e7d0ade68e1d1a0ee93c8370edf6e415) (cherry picked from commit on googleplex-android-review.googlesource.com host: b323776b1b205a4b266e16fbdc4095871cc4d9ec) Merged-In: I4cd7e62e6800897cce50a5376495c499a0b9ad10 --- .../core/java/com/android/server/policy/PhoneWindowManager.java | 4 ++-- .../core/java/com/android/server/policy/WindowManagerPolicy.java | 3 ++- services/core/java/com/android/server/wm/KeyguardController.java | 6 ++++-- .../wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5285f63dcc44..adc74e6cab5d 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3312,8 +3312,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } @Override - public void onKeyguardOccludedChangedLw(boolean occluded) { - if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) { + public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) { + if (mKeyguardDelegate != null && waitAppTransition) { mPendingKeyguardOccluded = occluded; mKeyguardOccludedChanged = true; } else { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 4f00992c713e..77007fa229a2 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -166,9 +166,10 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** * Called when the Keyguard occluded state changed. + * * @param occluded Whether Keyguard is currently occluded or not. */ - void onKeyguardOccludedChangedLw(boolean occluded); + void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition); /** * Applies a keyguard occlusion change if one happened. diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 48258a11d13a..1d21b9d8c141 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -403,8 +403,10 @@ class KeyguardController { return; } - mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY)); - if (isKeyguardLocked(displayId)) { + final boolean waitAppTransition = isKeyguardLocked(displayId); + mWindowManager.mPolicy.onKeyguardOccludedChangedLw(isDisplayOccluded(DEFAULT_DISPLAY), + waitAppTransition); + if (waitAppTransition) { mService.deferWindowLayout(); try { mRootWindowContainer.getDefaultDisplay() diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index d2cb7ba5d311..e2db2e6b19e1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -222,7 +222,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void onKeyguardOccludedChangedLw(boolean occluded) { + public void onKeyguardOccludedChangedLw(boolean occluded, boolean waitAppTransition) { } public void setSafeMode(boolean safeMode) { -- cgit v1.2.3 From dd827701a3de3dd35753fa8b39a5054049449e68 Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Thu, 9 Feb 2023 12:28:26 -0800 Subject: Checks if AccessibilityServiceInfo is within parcelable size. - If too large when parsing service XMLs then skip this service. - If too large when a service attempts to update its own info then throw an error. Bug: 261589597 Test: atest AccessibilityServiceInfoTest Change-Id: Iffc0cd48cc713f7904d68059e141cb7de5a4b906 Merged-In: Iffc0cd48cc713f7904d68059e141cb7de5a4b906 (cherry picked from commit on googleplex-android-review.googlesource.com host: 553232c29079fbeab28f95307d025c1426aa7142) Merged-In: Iffc0cd48cc713f7904d68059e141cb7de5a4b906 --- .../android/accessibilityservice/AccessibilityService.java | 4 ++++ .../android/accessibilityservice/AccessibilityServiceInfo.java | 10 ++++++++++ .../server/accessibility/AccessibilityManagerService.java | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index c17fbf19516b..dd955406e690 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -2523,6 +2523,10 @@ public abstract class AccessibilityService extends Service { IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId); if (mInfo != null && connection != null) { + if (!mInfo.isWithinParcelableSize()) { + throw new IllegalStateException( + "Cannot update service info: size is larger than safe parcelable limits."); + } try { connection.setServiceInfo(mInfo); mInfo = null; diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 530de0f3af6b..0cbcdb5a2b62 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -40,6 +40,7 @@ import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; import android.hardware.fingerprint.FingerprintManager; import android.os.Build; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; @@ -1128,6 +1129,15 @@ public class AccessibilityServiceInfo implements Parcelable { return 0; } + /** @hide */ + public final boolean isWithinParcelableSize() { + final Parcel parcel = Parcel.obtain(); + writeToParcel(parcel, 0); + final boolean result = parcel.dataSize() <= IBinder.MAX_IPC_SIZE; + parcel.recycle(); + return result; + } + public void writeToParcel(Parcel parcel, int flagz) { parcel.writeInt(eventTypes); parcel.writeStringArray(packageNames); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 29194c58bd0c..3818a884c94a 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1848,6 +1848,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub AccessibilityServiceInfo accessibilityServiceInfo; try { accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); + if (!accessibilityServiceInfo.isWithinParcelableSize()) { + Slog.e(LOG_TAG, "Skipping service " + + accessibilityServiceInfo.getResolveInfo().getComponentInfo() + + " because service info size is larger than safe parcelable limits."); + continue; + } if (userState.mCrashedServices.contains(serviceInfo.getComponentName())) { // Restore the crashed attribute. accessibilityServiceInfo.crashed = true; -- cgit v1.2.3 From 916c9d8adcfbf92da02d167c7a2b1ae9ddeb6cfd Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 15 Feb 2023 15:20:25 -0800 Subject: Limit the number of shortcuts per app that can be retained by system This is a second attempt at fixing the issue, the previous CL ag/20642213 was reverted because it simply throws an exception when the limit is reached, which causes apps to crash since chat apps tends to be sending large amount of conversation shortcuts and they have no way to know how many of these shortcuts are still cached by the system. Instead of throwing an exception, this CL simply removes excessive shortcuts to avoid crashes. Currently there is a limit on the number of shortcuts an app can publish in respect to each launcher activity. This CL further implements a global maximum of total number of shortcuts that can be retained for an app to mitigate from any potential system health issue. When the global maximum is reached, ShortcutService will proactively removes shortcuts from system memory. Cached shortcuts are removed first, followed by dynamic shortcuts, using last updated time as tie-breaker. This CL additionally addresses an unexpected flow where re-publishing previously removed shortcuts that are still retained by the system could cause the total number of shortcuts to exceed previously set limit. Bug: 250576066 233155034 Test: manual Change-Id: I001c7a87b62aefa9487bf8efaf3cd02d7cb21521 (cherry picked from commit on googleplex-android-review.googlesource.com host: a6e7958ab84edbd9e5f4653d4d1f56a7438cd7dc) Merged-In: I001c7a87b62aefa9487bf8efaf3cd02d7cb21521 --- .../com/android/server/pm/ShortcutPackage.java | 99 +++++++++++++++++++--- .../com/android/server/pm/ShortcutService.java | 25 +++++- 2 files changed, 112 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 890c89152a7c..8507ad028a19 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -430,6 +430,7 @@ class ShortcutPackage extends ShortcutPackageItem { @NonNull List changedShortcuts) { Preconditions.checkArgument(newShortcut.isEnabled(), "pushDynamicShortcuts() cannot publish disabled shortcuts"); + ensureShortcutCountBeforePush(); newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); @@ -437,7 +438,7 @@ class ShortcutPackage extends ShortcutPackageItem { final ShortcutInfo oldShortcut = findShortcutById(newShortcut.getId()); boolean deleted = false; - if (oldShortcut == null) { + if (oldShortcut == null || !oldShortcut.isDynamic()) { final ShortcutService service = mShortcutUser.mService; final int maxShortcuts = service.getMaxActivityShortcuts(); @@ -446,18 +447,12 @@ class ShortcutPackage extends ShortcutPackageItem { final ArrayList activityShortcuts = all.get(newShortcut.getActivity()); if (activityShortcuts != null && activityShortcuts.size() > maxShortcuts) { - Slog.e(TAG, "Error pushing shortcut. There are already " - + activityShortcuts.size() + " shortcuts, exceeding the " + maxShortcuts - + " shortcuts limit when pushing the new shortcut " + newShortcut - + ". Id of shortcuts currently available in system memory are " - + activityShortcuts.stream().map(ShortcutInfo::getId) - .collect(Collectors.joining(",", "[", "]"))); - // TODO: This should not have happened. If it does, identify the root cause where - // possible, otherwise bail-out early to prevent memory issue. + // Root cause was discovered in b/233155034, so this should not be happening. + service.wtf("Error pushing shortcut. There are already " + + activityShortcuts.size() + " shortcuts."); } if (activityShortcuts != null && activityShortcuts.size() == maxShortcuts) { // Max has reached. Delete the shortcut with lowest rank. - // Sort by isManifestShortcut() and getRank(). Collections.sort(activityShortcuts, mShortcutTypeAndRankComparator); @@ -473,7 +468,8 @@ class ShortcutPackage extends ShortcutPackageItem { deleted = deleteDynamicWithId(shortcut.getId(), /* ignoreInvisible =*/ true, /*ignorePersistedShortcuts=*/ true) != null; } - } else { + } + if (oldShortcut != null) { // It's an update case. // Make sure the target is updatable. (i.e. should be mutable.) oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); @@ -505,6 +501,32 @@ class ShortcutPackage extends ShortcutPackageItem { return deleted; } + private void ensureShortcutCountBeforePush() { + final ShortcutService service = mShortcutUser.mService; + // Ensure the total number of shortcuts doesn't exceed the hard limit per app. + final int maxShortcutPerApp = service.getMaxAppShortcuts(); + synchronized (mLock) { + final List appShortcuts = mShortcuts.values().stream().filter(si -> + !si.isPinned()).collect(Collectors.toList()); + if (appShortcuts.size() >= maxShortcutPerApp) { + // Max has reached. Removes shortcuts until they fall within the hard cap. + // Sort by isManifestShortcut(), isDynamic() and getLastChangedTimestamp(). + Collections.sort(appShortcuts, mShortcutTypeRankAndTimeComparator); + + while (appShortcuts.size() >= maxShortcutPerApp) { + final ShortcutInfo shortcut = appShortcuts.remove(appShortcuts.size() - 1); + if (shortcut.isDeclaredInManifest()) { + // All shortcuts are manifest shortcuts and cannot be removed. + throw new IllegalArgumentException(getPackageName() + " has published " + + appShortcuts.size() + " manifest shortcuts across different" + + " activities."); + } + forceDeleteShortcutInner(shortcut.getId()); + } + } + } + } + /** * Remove all shortcuts that aren't pinned, cached nor dynamic. * @@ -1366,6 +1388,61 @@ class ShortcutPackage extends ShortcutPackageItem { return Integer.compare(a.getRank(), b.getRank()); }; + /** + * To sort by isManifestShortcut(), isDynamic(), getRank() and + * getLastChangedTimestamp(). i.e. manifest shortcuts come before non-manifest shortcuts, + * dynamic shortcuts come before floating shortcuts, then sort by last changed timestamp. + * + * This is used to decide which shortcuts to remove when the total number of shortcuts retained + * for the app exceeds the limit defined in {@link ShortcutService#getMaxAppShortcuts()}. + * + * (Note the number of manifest shortcuts is always <= the max number, because if there are + * more, ShortcutParser would ignore the rest.) + */ + final Comparator mShortcutTypeRankAndTimeComparator = (ShortcutInfo a, + ShortcutInfo b) -> { + if (a.isDeclaredInManifest() && !b.isDeclaredInManifest()) { + return -1; + } + if (!a.isDeclaredInManifest() && b.isDeclaredInManifest()) { + return 1; + } + if (a.isDynamic() && b.isDynamic()) { + return Integer.compare(a.getRank(), b.getRank()); + } + if (a.isDynamic()) { + return -1; + } + if (b.isDynamic()) { + return 1; + } + if (a.isCached() && b.isCached()) { + // if both shortcuts are cached, prioritize shortcuts cached by people tile, + if (a.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE) + && !b.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE)) { + return -1; + } else if (!a.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE) + && b.hasFlags(ShortcutInfo.FLAG_CACHED_PEOPLE_TILE)) { + return 1; + } + // followed by bubbles. + if (a.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES) + && !b.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)) { + return -1; + } else if (!a.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES) + && b.hasFlags(ShortcutInfo.FLAG_CACHED_BUBBLES)) { + return 1; + } + } + if (a.isCached()) { + return -1; + } + if (b.isCached()) { + return 1; + } + return Long.compare(b.getLastChangedTimestamp(), a.getLastChangedTimestamp()); + }; + /** * Build a list of shortcuts for each target activity and return as a map. The result won't * contain "floating" shortcuts because they don't belong on any activities. diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 0b20683185f0..f303fedde567 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -180,6 +180,9 @@ public class ShortcutService extends IShortcutService.Stub { @VisibleForTesting static final int DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY = 15; + @VisibleForTesting + static final int DEFAULT_MAX_SHORTCUTS_PER_APP = 100; + @VisibleForTesting static final int DEFAULT_MAX_ICON_DIMENSION_DP = 96; @@ -256,6 +259,11 @@ public class ShortcutService extends IShortcutService.Stub { */ String KEY_MAX_SHORTCUTS = "max_shortcuts"; + /** + * Key name for the max shortcuts can be retained in system ram per app. (int) + */ + String KEY_MAX_SHORTCUTS_PER_APP = "max_shortcuts_per_app"; + /** * Key name for icon compression quality, 0-100. */ @@ -329,10 +337,15 @@ public class ShortcutService extends IShortcutService.Stub { new SparseArray<>(); /** - * Max number of dynamic + manifest shortcuts that each application can have at a time. + * Max number of dynamic + manifest shortcuts that each activity can have at a time. */ private int mMaxShortcuts; + /** + * Max number of shortcuts that can exists in system ram for each application. + */ + private int mMaxShortcutsPerApp; + /** * Max number of updating API calls that each application can make during the interval. */ @@ -807,6 +820,9 @@ public class ShortcutService extends IShortcutService.Stub { mMaxShortcuts = Math.max(0, (int) parser.getLong( ConfigConstants.KEY_MAX_SHORTCUTS, DEFAULT_MAX_SHORTCUTS_PER_ACTIVITY)); + mMaxShortcutsPerApp = Math.max(0, (int) parser.getLong( + ConfigConstants.KEY_MAX_SHORTCUTS_PER_APP, DEFAULT_MAX_SHORTCUTS_PER_APP)); + final int iconDimensionDp = Math.max(1, injectIsLowRamDevice() ? (int) parser.getLong( ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM, @@ -1758,6 +1774,13 @@ public class ShortcutService extends IShortcutService.Stub { return mMaxShortcuts; } + /** + * Return the max number of shortcuts can be retaiend in system ram for each application. + */ + int getMaxAppShortcuts() { + return mMaxShortcutsPerApp; + } + /** * - Sends a notification to LauncherApps * - Write to file -- cgit v1.2.3 From beb119d4f4990ddce8e75a93ab134a17603614b0 Mon Sep 17 00:00:00 2001 From: Mark Renouf Date: Wed, 22 Feb 2023 14:15:04 +0000 Subject: Prevent sharesheet from previewing unowned URIs [RESTRICT AUTOMERGE] Bug: 261036568 Test: manually via supplied tool (see bug) Change-Id: Iee1a75ef6ecbf471badeb42d8ebea11e74d884c1 Merged-In: I83e93c373538460e38ec17f1fd8e39d7aea95c10 (cherry picked from commit on googleplex-android-review.googlesource.com host: cef32a8b8ad109cd3066e4ad249fadbb72aa5574) Merged-In: Iee1a75ef6ecbf471badeb42d8ebea11e74d884c1 --- .../com/android/internal/app/ChooserActivity.java | 35 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 1fcfe7dd5b6f..09c1efb2c638 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL; import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK; import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE; +import static android.content.ContentProvider.getUserIdFromUri; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL; import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK; @@ -161,6 +162,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Supplier; +import java.util.stream.Collectors; /** * The Chooser Activity handles intent resolution specifically for sharing intents - @@ -1424,7 +1426,11 @@ public class ChooserActivity extends ResolverActivity implements String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { - Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM, android.net.Uri.class); + if (!validForContentPreview(uri)) { + contentPreviewLayout.setVisibility(View.GONE); + return contentPreviewLayout; + } imagePreview.findViewById(R.id.content_preview_image_1_large) .setTransitionName(ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME); mPreviewCoord.loadUriIntoView(R.id.content_preview_image_1_large, uri, 0); @@ -1434,7 +1440,7 @@ public class ChooserActivity extends ResolverActivity implements List uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); List imageUris = new ArrayList<>(); for (Uri uri : uris) { - if (isImageType(resolver.getType(uri))) { + if (validForContentPreview(uri) && isImageType(resolver.getType(uri))) { imageUris.add(uri); } } @@ -1544,9 +1550,16 @@ public class ChooserActivity extends ResolverActivity implements String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { Uri uri = targetIntent.getParcelableExtra(Intent.EXTRA_STREAM); + if (!validForContentPreview(uri)) { + contentPreviewLayout.setVisibility(View.GONE); + return contentPreviewLayout; + } loadFileUriIntoView(uri, contentPreviewLayout); } else { List uris = targetIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + uris = uris.stream() + .filter(ChooserActivity::validForContentPreview) + .collect(Collectors.toList()); int uriCount = uris.size(); if (uriCount == 0) { @@ -1605,6 +1618,24 @@ public class ChooserActivity extends ResolverActivity implements } } + /** + * Indicate if the incoming content URI should be allowed. + * + * @param uri the uri to test + * @return true if the URI is allowed for content preview + */ + private static boolean validForContentPreview(Uri uri) throws SecurityException { + if (uri == null) { + return false; + } + int userId = getUserIdFromUri(uri, UserHandle.USER_CURRENT); + if (userId != UserHandle.USER_CURRENT && userId != UserHandle.myUserId()) { + Log.e(TAG, "dropped invalid content URI belonging to user " + userId); + return false; + } + return true; + } + @VisibleForTesting protected boolean isImageType(String mimeType) { return mimeType != null && mimeType.startsWith("image/"); -- cgit v1.2.3 From 5d02b49fa02ac4402bbb8869935443721355351d Mon Sep 17 00:00:00 2001 From: Thomas Stuart Date: Mon, 21 Nov 2022 17:38:21 -0800 Subject: enforce stricter rules when registering phoneAccounts - include disable accounts when looking up accounts for a package to check if the limit is reached (10) - put a new limit of 10 supported schemes - put a new limit of 256 characters per scheme - put a new limit of 256 characters per address - ensure the Icon can write to memory w/o throwing an exception bug: 259064622 bug: 256819769 Test: cts + unit Change-Id: Ia7d8d00d9de0fb6694ded6a80c40bd55d7fdf7a7 Merged-In: Ia7d8d00d9de0fb6694ded6a80c40bd55d7fdf7a7 (cherry picked from commit on googleplex-android-review.googlesource.com host: b07326f1fb3d0e42a6bab902c271974c42d93c06) Merged-In: Ia7d8d00d9de0fb6694ded6a80c40bd55d7fdf7a7 --- telecomm/java/android/telecom/PhoneAccount.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index ec18c6a696b8..7a53447c1eee 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -555,6 +555,11 @@ public final class PhoneAccount implements Parcelable { /** * Sets the address. See {@link PhoneAccount#getAddress}. + *

+ * Note: The entire URI value is limited to 256 characters. This check is + * enforced when registering the PhoneAccount via + * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} and will cause an + * {@link IllegalArgumentException} to be thrown if URI is over 256. * * @param value The address of the phone account. * @return The builder. @@ -588,6 +593,10 @@ public final class PhoneAccount implements Parcelable { /** * Sets the icon. See {@link PhoneAccount#getIcon}. + *

+ * Note: An {@link IllegalArgumentException} if the Icon cannot be written to memory. + * This check is enforced when registering the PhoneAccount via + * {@link TelecomManager#registerPhoneAccount(PhoneAccount)} * * @param icon The icon to set. */ @@ -621,6 +630,10 @@ public final class PhoneAccount implements Parcelable { /** * Specifies an additional URI scheme supported by the {@link PhoneAccount}. * + *

+ * Each URI scheme is limited to 256 characters. Adding a scheme over 256 characters will + * cause an {@link IllegalArgumentException} to be thrown when the account is registered. + * * @param uriScheme The URI scheme. * @return The builder. */ @@ -634,6 +647,12 @@ public final class PhoneAccount implements Parcelable { /** * Specifies the URI schemes supported by the {@link PhoneAccount}. * + *

+ * A max of 10 URI schemes can be added per account. Additionally, each URI scheme is + * limited to 256 characters. Adding more than 10 URI schemes or 256 characters on any + * scheme will cause an {@link IllegalArgumentException} to be thrown when the account + * is registered. + * * @param uriSchemes The URI schemes. * @return The builder. */ -- cgit v1.2.3 From 7068be19255fb6f77b6c8218bfbcd2fa843261ce Mon Sep 17 00:00:00 2001 From: Mugdha Lakhani Date: Thu, 29 Dec 2022 15:18:07 +0000 Subject: DO NOT MERGE Isolated processes must fail registering BRs. Broadcast Receivers should not be allowed to be registered by isolated processes. Bug: b/263358101 Test: atest SdkSandboxRestrictionsHostTest Change-Id: I5bb2ee3ce8a447105a18851fdffa5a769cc3fe49 (cherry picked from commit 43b8a91b0584dd1c6a136702e68e1f0cd519cb51) (cherry picked from commit on googleplex-android-review.googlesource.com host: d752ea5f24ce50f407504ce99f56535d4cece8e2) Merged-In: I5bb2ee3ce8a447105a18851fdffa5a769cc3fe49 --- .../java/com/android/server/am/ActivityManagerService.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1428fa853f2a..3e43e711e7f5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -13087,12 +13087,17 @@ public class ActivityManagerService extends IActivityManager.Stub public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, String callerFeatureId, String receiverId, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { + enforceNotIsolatedCaller("registerReceiver"); + // Allow Sandbox process to register only unexported receivers. - if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) { - enforceNotIsolatedCaller("registerReceiver"); - } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) { - enforceNotIsolatedOrSdkSandboxCaller("registerReceiver"); + boolean unexported = (flags & Context.RECEIVER_NOT_EXPORTED) != 0; + if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced() + && Process.isSdkSandboxUid(Binder.getCallingUid()) + && !unexported) { + throw new SecurityException("SDK sandbox process not allowed to call " + + "registerReceiver"); } + ArrayList stickyIntents = null; ProcessRecord callerApp = null; final boolean visibleToInstantApps -- cgit v1.2.3