From bb4bfcc575aad63c7ce7d07f4767b4d5005c2d41 Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Tue, 6 Oct 2020 09:17:39 -0400 Subject: [DO NOT MERGE] Make GlobalScreenshot PendingIntents immutable Mutable pending intents are a security risk. This change adds the IMMUTABLE flag to all PendingIntents created in GlobalScreenshot. Bug: 162738636 Test: manual Change-Id: I1044b6aaf2b1650ff91d9a72181684d2aaea9a62 --- .../systemui/screenshot/GlobalScreenshot.java | 108 ++++++++++++--------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index 9b30a77003cd..3576d6b21938 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -135,6 +135,7 @@ class SaveImageInBackgroundData { imageUri = null; iconSize = 0; } + void clearContext() { context = null; } @@ -234,13 +235,13 @@ class SaveImageInBackgroundTask extends AsyncTask { mNotificationBuilder = new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP) - .setContentTitle(r.getString(R.string.screenshot_saving_title)) - .setSmallIcon(R.drawable.stat_notify_image) - .setWhen(now) - .setShowWhen(true) - .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color)) - .setStyle(mNotificationStyle) - .setPublicVersion(mPublicNotificationBuilder.build()); + .setContentTitle(r.getString(R.string.screenshot_saving_title)) + .setSmallIcon(R.drawable.stat_notify_image) + .setWhen(now) + .setShowWhen(true) + .setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color)) + .setStyle(mNotificationStyle) + .setPublicVersion(mPublicNotificationBuilder.build()); mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true); SystemUI.overrideNotificationAppName(context, mNotificationBuilder, true); @@ -277,7 +278,7 @@ class SaveImageInBackgroundTask extends AsyncTask { PendingIntent broadcastIntent = PendingIntent.getBroadcast(context, mRandom.nextInt(), intent, - PendingIntent.FLAG_CANCEL_CURRENT); + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); broadcastActions.add(new Notification.Action.Builder(action.getIcon(), action.title, broadcastIntent).setContextual(true).addExtras(extras).build()); } @@ -287,9 +288,9 @@ class SaveImageInBackgroundTask extends AsyncTask { private static void addIntentExtras(String screenshotId, Intent intent, String actionType, boolean smartActionsEnabled) { intent - .putExtra(GlobalScreenshot.EXTRA_ACTION_TYPE, actionType) - .putExtra(GlobalScreenshot.EXTRA_ID, screenshotId) - .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, smartActionsEnabled); + .putExtra(GlobalScreenshot.EXTRA_ACTION_TYPE, actionType) + .putExtra(GlobalScreenshot.EXTRA_ID, screenshotId) + .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, smartActionsEnabled); } private int getUserHandleOfForegroundApplication(Context context) { @@ -411,7 +412,9 @@ class SaveImageInBackgroundTask extends AsyncTask { PendingIntent chooserAction = PendingIntent.getBroadcast(context, 0, new Intent(context, GlobalScreenshot.TargetChosenReceiver.class), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + PendingIntent.FLAG_CANCEL_CURRENT + | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE); Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null, chooserAction.getIntentSender()) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK) @@ -425,7 +428,8 @@ class SaveImageInBackgroundTask extends AsyncTask { .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, mSmartActionsEnabled), - PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, + UserHandle.SYSTEM); Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder( R.drawable.ic_screenshot_share, r.getString(com.android.internal.R.string.share), shareAction); @@ -451,7 +455,8 @@ class SaveImageInBackgroundTask extends AsyncTask { .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, mSmartActionsEnabled), - PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM); + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE, + UserHandle.SYSTEM); Notification.Action.Builder editActionBuilder = new Notification.Action.Builder( R.drawable.ic_screenshot_edit, r.getString(com.android.internal.R.string.screenshot_edit), editAction); @@ -464,7 +469,9 @@ class SaveImageInBackgroundTask extends AsyncTask { .putExtra(GlobalScreenshot.EXTRA_ID, mScreenshotId) .putExtra(GlobalScreenshot.EXTRA_SMART_ACTIONS_ENABLED, mSmartActionsEnabled), - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT); + PendingIntent.FLAG_CANCEL_CURRENT + | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE); Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder( R.drawable.ic_screenshot_delete, r.getString(com.android.internal.R.string.delete), deleteAction); @@ -507,21 +514,23 @@ class SaveImageInBackgroundTask extends AsyncTask { mPublicNotificationBuilder .setContentTitle(r.getString(R.string.screenshot_saved_title)) .setContentText(r.getString(R.string.screenshot_saved_text)) - .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0)) + .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, + PendingIntent.FLAG_IMMUTABLE)) .setWhen(now) .setAutoCancel(true) .setColor(context.getColor( com.android.internal.R.color.system_notification_accent_color)); mNotificationBuilder - .setContentTitle(r.getString(R.string.screenshot_saved_title)) - .setContentText(r.getString(R.string.screenshot_saved_text)) - .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, 0)) - .setWhen(now) - .setAutoCancel(true) - .setColor(context.getColor( - com.android.internal.R.color.system_notification_accent_color)) - .setPublicVersion(mPublicNotificationBuilder.build()) - .setFlag(Notification.FLAG_NO_CLEAR, false); + .setContentTitle(r.getString(R.string.screenshot_saved_title)) + .setContentText(r.getString(R.string.screenshot_saved_text)) + .setContentIntent(PendingIntent.getActivity(mParams.context, 0, launchIntent, + PendingIntent.FLAG_IMMUTABLE)) + .setWhen(now) + .setAutoCancel(true) + .setColor(context.getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setPublicVersion(mPublicNotificationBuilder.build()) + .setFlag(Notification.FLAG_NO_CLEAR, false); mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT, mNotificationBuilder.build()); @@ -633,7 +642,8 @@ class GlobalScreenshot { // Inflate the screenshot layout mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null); - mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background); + mBackgroundView = (ImageView) mScreenshotLayout.findViewById( + R.id.global_screenshot_background); mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot); mScreenshotFlash = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_flash); mScreenshotSelectorView = (ScreenshotSelectorView) mScreenshotLayout.findViewById( @@ -654,25 +664,25 @@ class GlobalScreenshot { ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0, WindowManager.LayoutParams.TYPE_SCREENSHOT, WindowManager.LayoutParams.FLAG_FULLSCREEN - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, + | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN + | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, PixelFormat.TRANSLUCENT); mWindowLayoutParams.setTitle("ScreenshotAnimation"); mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mNotificationManager = - (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); + (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE); mDisplay = mWindowManager.getDefaultDisplay(); mDisplayMetrics = new DisplayMetrics(); mDisplay.getRealMetrics(mDisplayMetrics); // Get the various target sizes mNotificationIconSize = - r.getDimensionPixelSize(android.R.dimen.notification_large_icon_height); + r.getDimensionPixelSize(android.R.dimen.notification_large_icon_height); // Scale has to account for both sides of the bg mBgPadding = (float) r.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding); - mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels; + mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels; // determine the optimal preview size int panelWidth = 0; @@ -857,6 +867,7 @@ class GlobalScreenshot { } }); } + private ValueAnimator createScreenshotDropInAnimation() { final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION) / SCREENSHOT_DROP_IN_DURATION); @@ -906,6 +917,7 @@ class GlobalScreenshot { mScreenshotFlash.setAlpha(0f); mScreenshotFlash.setVisibility(View.VISIBLE); } + @Override public void onAnimationEnd(android.animation.Animator animation) { mScreenshotFlash.setVisibility(View.GONE); @@ -916,7 +928,7 @@ class GlobalScreenshot { public void onAnimationUpdate(ValueAnimator animation) { float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale) - - scaleInterpolator.getInterpolation(t) + - scaleInterpolator.getInterpolation(t) * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE); mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA); mScreenshotView.setAlpha(t); @@ -927,6 +939,7 @@ class GlobalScreenshot { }); return anim; } + private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible, boolean navBarVisible) { ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); @@ -948,7 +961,8 @@ class GlobalScreenshot { public void onAnimationUpdate(ValueAnimator animation) { float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale) - - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE); + - t * (SCREENSHOT_DROP_IN_MIN_SCALE + - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE); mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA); mScreenshotView.setAlpha(1f - t); mScreenshotView.setScaleX(scaleT); @@ -975,8 +989,10 @@ class GlobalScreenshot { float halfScreenHeight = (h - 2f * mBgPadding) / 2f; final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET; final PointF finalPos = new PointF( - -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth, - -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight); + -halfScreenWidth + + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth, + -halfScreenHeight + + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight); // Animate the screenshot to the status bar anim.setDuration(SCREENSHOT_DROP_OUT_DURATION); @@ -985,7 +1001,7 @@ class GlobalScreenshot { public void onAnimationUpdate(ValueAnimator animation) { float t = (Float) animation.getAnimatedValue(); float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale) - - scaleInterpolator.getInterpolation(t) + - scaleInterpolator.getInterpolation(t) * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE); mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA); mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t)); @@ -1005,15 +1021,15 @@ class GlobalScreenshot { // Repurpose the existing notification to notify the user of the error Notification.Builder b = new Notification.Builder(context, NotificationChannels.ALERTS) - .setTicker(r.getString(R.string.screenshot_failed_title)) - .setContentTitle(r.getString(R.string.screenshot_failed_title)) - .setContentText(errorMsg) - .setSmallIcon(R.drawable.stat_notify_image_error) - .setWhen(System.currentTimeMillis()) - .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen - .setCategory(Notification.CATEGORY_ERROR) - .setAutoCancel(true) - .setColor(context.getColor( + .setTicker(r.getString(R.string.screenshot_failed_title)) + .setContentTitle(r.getString(R.string.screenshot_failed_title)) + .setContentText(errorMsg) + .setSmallIcon(R.drawable.stat_notify_image_error) + .setWhen(System.currentTimeMillis()) + .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen + .setCategory(Notification.CATEGORY_ERROR) + .setAutoCancel(true) + .setColor(context.getColor( com.android.internal.R.color.system_notification_accent_color)); final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( Context.DEVICE_POLICY_SERVICE); @@ -1021,7 +1037,7 @@ class GlobalScreenshot { DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE); if (intent != null) { final PendingIntent pendingIntent = PendingIntent.getActivityAsUser( - context, 0, intent, 0, null, UserHandle.CURRENT); + context, 0, intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT); b.setContentIntent(pendingIntent); } -- cgit v1.2.3-59-g8ed1b