Loading core/java/android/app/ActivityManagerInternal.java +15 −0 Original line number Diff line number Diff line Loading @@ -273,4 +273,19 @@ public abstract class ActivityManagerInternal { * Returns {@code true} if {@code uid} is running an activity from {@code packageName}. */ public abstract boolean hasRunningActivity(int uid, @Nullable String packageName); /** * Returns {@code true} if the given notification channel currently has a * notification associated with a foreground service. This is an AMS check * because that is the source of truth for the FGS state. */ public abstract boolean hasForegroundServiceNotification(String pkg, int userId, String channelId); /** * If the given app has any FGSs whose notifications are in the given channel, * stop them. */ public abstract void stopForegroundServicesForChannel(String pkg, int userId, String channelId); } packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +27 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Parcelable; Loading Loading @@ -72,6 +73,16 @@ public class StatusBarIconView extends AnimatedImageView { public static final int STATE_DOT = 1; public static final int STATE_HIDDEN = 2; /** * Maximum allowed byte count for an icon bitmap * @see android.graphics.RecordingCanvas.MAX_BITMAP_SIZE */ private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB /** * Maximum allowed width or height for an icon drawable, if we can't get byte count */ private static final int MAX_IMAGE_SIZE = 5000; private static final String TAG = "StatusBarIconView"; private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT = new FloatProperty<StatusBarIconView>("iconAppearAmount") { Loading Loading @@ -328,6 +339,22 @@ public class StatusBarIconView extends AnimatedImageView { Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon); return false; } if (drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() != null) { // If it's a bitmap we can check the size directly int byteCount = ((BitmapDrawable) drawable).getBitmap().getByteCount(); if (byteCount > MAX_BITMAP_SIZE) { Log.w(TAG, "Drawable is too large (" + byteCount + " bytes) " + mIcon); return false; } } else if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) { // Otherwise, check dimensions Log.w(TAG, "Drawable is too large (" + drawable.getIntrinsicWidth() + "x" + drawable.getIntrinsicHeight() + ") " + mIcon); return false; } if (withClear) { setImageDrawable(null); } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Icon; import android.os.UserHandle; Loading Loading @@ -122,4 +123,13 @@ public class StatusBarIconViewTest extends SysuiTestCase { assertEquals("Transparent backgrounds should fallback to drawable color", color, mIconView.getStaticDrawableColor()); } @Test public void testGiantImageNotAllowed() { Bitmap largeBitmap = Bitmap.createBitmap(6000, 6000, Bitmap.Config.ARGB_8888); Icon icon = Icon.createWithBitmap(largeBitmap); StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", icon, 0, 0, ""); assertFalse(mIconView.set(largeIcon)); } } No newline at end of file services/core/java/com/android/server/am/ActiveServices.java +40 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import android.app.ActivityThread; Loading Loading @@ -311,6 +312,45 @@ public final class ActiveServices { return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false; } boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) { final ServiceMap smap = mServiceMap.get(userId); if (smap != null) { for (int i = 0; i < smap.mServicesByName.size(); i++) { final ServiceRecord sr = smap.mServicesByName.valueAt(i); if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg + "/channelId=" + channelId + " has fg service notification"); } return true; } } } } return false; } void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) { final ServiceMap smap = mServiceMap.get(userId); if (smap != null) { for (int i = 0; i < smap.mServicesByName.size(); i++) { final ServiceRecord sr = smap.mServicesByName.valueAt(i); if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg + "/channelId=" + channelId + " for conversation channel clear"); } stopServiceLocked(sr); } } } } } private ServiceMap getServiceMapLocked(int callingUser) { ServiceMap smap = mServiceMap.get(callingUser); if (smap == null) { Loading services/core/java/com/android/server/am/ActivityManagerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -24372,6 +24372,23 @@ public class ActivityManagerService extends IActivityManager.Stub } return false; } @Override public boolean hasForegroundServiceNotification(String pkg, int userId, String channelId) { synchronized (ActivityManagerService.this) { return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId); } } @Override public void stopForegroundServicesForChannel(String pkg, int userId, String channelId) { synchronized (ActivityManagerService.this) { mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId); } } } /** Loading
core/java/android/app/ActivityManagerInternal.java +15 −0 Original line number Diff line number Diff line Loading @@ -273,4 +273,19 @@ public abstract class ActivityManagerInternal { * Returns {@code true} if {@code uid} is running an activity from {@code packageName}. */ public abstract boolean hasRunningActivity(int uid, @Nullable String packageName); /** * Returns {@code true} if the given notification channel currently has a * notification associated with a foreground service. This is an AMS check * because that is the source of truth for the FGS state. */ public abstract boolean hasForegroundServiceNotification(String pkg, int userId, String channelId); /** * If the given app has any FGSs whose notifications are in the given channel, * stop them. */ public abstract void stopForegroundServicesForChannel(String pkg, int userId, String channelId); }
packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +27 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.Parcelable; Loading Loading @@ -72,6 +73,16 @@ public class StatusBarIconView extends AnimatedImageView { public static final int STATE_DOT = 1; public static final int STATE_HIDDEN = 2; /** * Maximum allowed byte count for an icon bitmap * @see android.graphics.RecordingCanvas.MAX_BITMAP_SIZE */ private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB /** * Maximum allowed width or height for an icon drawable, if we can't get byte count */ private static final int MAX_IMAGE_SIZE = 5000; private static final String TAG = "StatusBarIconView"; private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT = new FloatProperty<StatusBarIconView>("iconAppearAmount") { Loading Loading @@ -328,6 +339,22 @@ public class StatusBarIconView extends AnimatedImageView { Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon); return false; } if (drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() != null) { // If it's a bitmap we can check the size directly int byteCount = ((BitmapDrawable) drawable).getBitmap().getByteCount(); if (byteCount > MAX_BITMAP_SIZE) { Log.w(TAG, "Drawable is too large (" + byteCount + " bytes) " + mIcon); return false; } } else if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) { // Otherwise, check dimensions Log.w(TAG, "Drawable is too large (" + drawable.getIntrinsicWidth() + "x" + drawable.getIntrinsicHeight() + ") " + mIcon); return false; } if (withClear) { setImageDrawable(null); } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Icon; import android.os.UserHandle; Loading Loading @@ -122,4 +123,13 @@ public class StatusBarIconViewTest extends SysuiTestCase { assertEquals("Transparent backgrounds should fallback to drawable color", color, mIconView.getStaticDrawableColor()); } @Test public void testGiantImageNotAllowed() { Bitmap largeBitmap = Bitmap.createBitmap(6000, 6000, Bitmap.Config.ARGB_8888); Icon icon = Icon.createWithBitmap(largeBitmap); StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage", icon, 0, 0, ""); assertFalse(mIconView.set(largeIcon)); } } No newline at end of file
services/core/java/com/android/server/am/ActiveServices.java +40 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import android.app.ActivityThread; Loading Loading @@ -311,6 +312,45 @@ public final class ActiveServices { return smap != null ? smap.mStartingBackground.size() >= mMaxStartingBackground : false; } boolean hasForegroundServiceNotificationLocked(String pkg, int userId, String channelId) { final ServiceMap smap = mServiceMap.get(userId); if (smap != null) { for (int i = 0; i < smap.mServicesByName.size(); i++) { final ServiceRecord sr = smap.mServicesByName.valueAt(i); if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Channel u" + userId + "/pkg=" + pkg + "/channelId=" + channelId + " has fg service notification"); } return true; } } } } return false; } void stopForegroundServicesForChannelLocked(String pkg, int userId, String channelId) { final ServiceMap smap = mServiceMap.get(userId); if (smap != null) { for (int i = 0; i < smap.mServicesByName.size(); i++) { final ServiceRecord sr = smap.mServicesByName.valueAt(i); if (sr.appInfo.packageName.equals(pkg) && sr.isForeground) { if (Objects.equals(sr.foregroundNoti.getChannelId(), channelId)) { if (DEBUG_FOREGROUND_SERVICE) { Slog.d(TAG_SERVICE, "Stopping FGS u" + userId + "/pkg=" + pkg + "/channelId=" + channelId + " for conversation channel clear"); } stopServiceLocked(sr); } } } } } private ServiceMap getServiceMapLocked(int callingUser) { ServiceMap smap = mServiceMap.get(callingUser); if (smap == null) { Loading
services/core/java/com/android/server/am/ActivityManagerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -24372,6 +24372,23 @@ public class ActivityManagerService extends IActivityManager.Stub } return false; } @Override public boolean hasForegroundServiceNotification(String pkg, int userId, String channelId) { synchronized (ActivityManagerService.this) { return mServices.hasForegroundServiceNotificationLocked(pkg, userId, channelId); } } @Override public void stopForegroundServicesForChannel(String pkg, int userId, String channelId) { synchronized (ActivityManagerService.this) { mServices.stopForegroundServicesForChannelLocked(pkg, userId, channelId); } } } /**