Merge "[DO NOT MERGE] Prevent RemoteViews crashing SystemUi" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2023-03-15 03:59:36 +00:00
committed by Android (Google) Code Review
7 changed files with 89 additions and 18 deletions

View File

@@ -31,6 +31,7 @@ import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps; import android.content.pm.LauncherApps;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect; import android.graphics.Rect;
@@ -311,19 +312,26 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
super.onLayout(changed, left, top, right, bottom); super.onLayout(changed, left, top, right, bottom);
} catch (final RuntimeException e) { } catch (final RuntimeException e) {
Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e); Log.e(TAG, "Remote provider threw runtime exception, using error view instead.", e);
removeViewInLayout(mView); handleViewError();
View child = getErrorView();
prepareView(child);
addViewInLayout(child, 0, child.getLayoutParams());
measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
mView = child;
mViewMode = VIEW_MODE_ERROR;
} }
} }
/**
* Remove bad view and replace with error message view
*/
private void handleViewError() {
removeViewInLayout(mView);
View child = getErrorView();
prepareView(child);
addViewInLayout(child, 0, child.getLayoutParams());
measureChild(child, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
child.layout(0, 0, child.getMeasuredWidth() + mPaddingLeft + mPaddingRight,
child.getMeasuredHeight() + mPaddingTop + mPaddingBottom);
mView = child;
mViewMode = VIEW_MODE_ERROR;
}
/** /**
* Provide guidance about the size of this widget to the AppWidgetManager. The widths and * Provide guidance about the size of this widget to the AppWidgetManager. The widths and
* heights should correspond to the full area the AppWidgetHostView is given. Padding added by * heights should correspond to the full area the AppWidgetHostView is given. Padding added by
@@ -953,4 +961,15 @@ public class AppWidgetHostView extends FrameLayout implements AppWidgetHost.AppW
reapplyLastRemoteViews(); reapplyLastRemoteViews();
} }
} }
@Override
protected void dispatchDraw(@NonNull Canvas canvas) {
try {
super.dispatchDraw(canvas);
} catch (Exception e) {
// Catch draw exceptions that may be caused by RemoteViews
Log.e(TAG, "Drawing view failed: " + e);
post(this::handleViewError);
}
}
} }

View File

@@ -73,6 +73,7 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ContrastColorUtil; import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.CachingIconView; import com.android.internal.widget.CachingIconView;
import com.android.internal.widget.CallLayout; import com.android.internal.widget.CallLayout;
@@ -1702,7 +1703,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
MetricsLogger metricsLogger, MetricsLogger metricsLogger,
SmartReplyConstants smartReplyConstants, SmartReplyConstants smartReplyConstants,
SmartReplyController smartReplyController, SmartReplyController smartReplyController,
FeatureFlags featureFlags) { FeatureFlags featureFlags,
IStatusBarService statusBarService) {
mEntry = entry; mEntry = entry;
mAppName = appName; mAppName = appName;
if (mMenuRow == null) { if (mMenuRow == null) {
@@ -1731,7 +1733,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mPeopleNotificationIdentifier, mPeopleNotificationIdentifier,
rivSubcomponentFactory, rivSubcomponentFactory,
smartReplyConstants, smartReplyConstants,
smartReplyController); smartReplyController,
statusBarService);
} }
mOnUserInteractionCallback = onUserInteractionCallback; mOnUserInteractionCallback = onUserInteractionCallback;
mBubblesManagerOptional = bubblesManagerOptional; mBubblesManagerOptional = bubblesManagerOptional;

View File

@@ -29,6 +29,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags; import com.android.systemui.flags.Flags;
@@ -100,6 +101,7 @@ public class ExpandableNotificationRowController implements NotifViewController
private final SmartReplyConstants mSmartReplyConstants; private final SmartReplyConstants mSmartReplyConstants;
private final SmartReplyController mSmartReplyController; private final SmartReplyController mSmartReplyController;
private final ExpandableNotificationRowDragController mDragController; private final ExpandableNotificationRowDragController mDragController;
private final IStatusBarService mStatusBarService;
private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback = private final ExpandableNotificationRow.ExpandableNotificationRowLogger mLoggerCallback =
new ExpandableNotificationRow.ExpandableNotificationRowLogger() { new ExpandableNotificationRow.ExpandableNotificationRowLogger() {
@Override @Override
@@ -157,7 +159,8 @@ public class ExpandableNotificationRowController implements NotifViewController
FeatureFlags featureFlags, FeatureFlags featureFlags,
PeopleNotificationIdentifier peopleNotificationIdentifier, PeopleNotificationIdentifier peopleNotificationIdentifier,
Optional<BubblesManager> bubblesManagerOptional, Optional<BubblesManager> bubblesManagerOptional,
ExpandableNotificationRowDragController dragController) { ExpandableNotificationRowDragController dragController,
IStatusBarService statusBarService) {
mView = view; mView = view;
mListContainer = listContainer; mListContainer = listContainer;
mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory; mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -189,6 +192,7 @@ public class ExpandableNotificationRowController implements NotifViewController
mLogBufferLogger = logBufferLogger; mLogBufferLogger = logBufferLogger;
mSmartReplyConstants = smartReplyConstants; mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController; mSmartReplyController = smartReplyController;
mStatusBarService = statusBarService;
} }
/** /**
@@ -220,7 +224,8 @@ public class ExpandableNotificationRowController implements NotifViewController
mMetricsLogger, mMetricsLogger,
mSmartReplyConstants, mSmartReplyConstants,
mSmartReplyController, mSmartReplyController,
mFeatureFlags mFeatureFlags,
mStatusBarService
); );
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) { if (mAllowLongPress) {

View File

@@ -21,10 +21,13 @@ import android.annotation.Nullable;
import android.app.Notification; import android.app.Notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.RemoteException;
import android.provider.Settings; import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.IndentingPrintWriter; import android.util.IndentingPrintWriter;
@@ -39,6 +42,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.RemoteInputController;
@@ -129,6 +133,7 @@ public class NotificationContentView extends FrameLayout implements Notification
private Runnable mExpandedVisibleListener; private Runnable mExpandedVisibleListener;
private PeopleNotificationIdentifier mPeopleIdentifier; private PeopleNotificationIdentifier mPeopleIdentifier;
private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory; private RemoteInputViewSubcomponent.Factory mRemoteInputSubcomponentFactory;
private IStatusBarService mStatusBarService;
/** /**
* List of listeners for when content views become inactive (i.e. not the showing view). * List of listeners for when content views become inactive (i.e. not the showing view).
@@ -196,11 +201,13 @@ public class NotificationContentView extends FrameLayout implements Notification
PeopleNotificationIdentifier peopleNotificationIdentifier, PeopleNotificationIdentifier peopleNotificationIdentifier,
RemoteInputViewSubcomponent.Factory rivSubcomponentFactory, RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
SmartReplyConstants smartReplyConstants, SmartReplyConstants smartReplyConstants,
SmartReplyController smartReplyController) { SmartReplyController smartReplyController,
IStatusBarService statusBarService) {
mPeopleIdentifier = peopleNotificationIdentifier; mPeopleIdentifier = peopleNotificationIdentifier;
mRemoteInputSubcomponentFactory = rivSubcomponentFactory; mRemoteInputSubcomponentFactory = rivSubcomponentFactory;
mSmartReplyConstants = smartReplyConstants; mSmartReplyConstants = smartReplyConstants;
mSmartReplyController = smartReplyController; mSmartReplyController = smartReplyController;
mStatusBarService = statusBarService;
} }
public void reinflate() { public void reinflate() {
@@ -2176,4 +2183,36 @@ public class NotificationContentView extends FrameLayout implements Notification
protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) { protected void setHeadsUpWrapper(NotificationViewWrapper headsUpWrapper) {
mHeadsUpWrapper = headsUpWrapper; mHeadsUpWrapper = headsUpWrapper;
} }
@Override
protected void dispatchDraw(Canvas canvas) {
try {
super.dispatchDraw(canvas);
} catch (Exception e) {
// Catch draw exceptions that may be caused by RemoteViews
Log.e(TAG, "Drawing view failed: " + e);
cancelNotification(e);
}
}
private void cancelNotification(Exception exception) {
try {
setVisibility(GONE);
final StatusBarNotification sbn = mNotificationEntry.getSbn();
if (mStatusBarService != null) {
// report notification inflation errors back up
// to notification delegates
mStatusBarService.onNotificationError(
sbn.getPackageName(),
sbn.getTag(),
sbn.getId(),
sbn.getUid(),
sbn.getInitialPid(),
exception.getMessage(),
sbn.getUser().getIdentifier());
}
} catch (RemoteException ex) {
Log.e(TAG, "cancelNotification failed: " + ex);
}
}
} }

View File

@@ -21,6 +21,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger import com.android.internal.logging.MetricsLogger
import com.android.internal.statusbar.IStatusBarService
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.FeatureFlags
@@ -93,6 +94,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock() private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
private val bubblesManager: BubblesManager = mock() private val bubblesManager: BubblesManager = mock()
private val dragController: ExpandableNotificationRowDragController = mock() private val dragController: ExpandableNotificationRowDragController = mock()
private val statusBarService: IStatusBarService = mock()
private lateinit var controller: ExpandableNotificationRowController private lateinit var controller: ExpandableNotificationRowController
@Before @Before
@@ -129,7 +131,8 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
featureFlags, featureFlags,
peopleNotificationIdentifier, peopleNotificationIdentifier,
Optional.of(bubblesManager), Optional.of(bubblesManager),
dragController dragController,
statusBarService
) )
whenever(view.childrenContainer).thenReturn(childrenContainer) whenever(view.childrenContainer).thenReturn(childrenContainer)
} }

View File

@@ -74,7 +74,7 @@ class NotificationContentViewTest : SysuiTestCase() {
doReturn(10).whenever(spyRow).intrinsicHeight doReturn(10).whenever(spyRow).intrinsicHeight
with(view) { with(view) {
initialize(mPeopleNotificationIdentifier, mock(), mock(), mock()) initialize(mPeopleNotificationIdentifier, mock(), mock(), mock(), mock())
setContainingNotification(spyRow) setContainingNotification(spyRow)
setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30) setHeights(/* smallHeight= */ 10, /* headsUpMaxHeight= */ 20, /* maxHeight= */ 30)
contractedChild = createViewWithHeight(10) contractedChild = createViewWithHeight(10)

View File

@@ -48,6 +48,7 @@ import android.view.LayoutInflater;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.TestableDependency; import com.android.systemui.TestableDependency;
import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.classifier.FalsingManagerFake;
@@ -548,7 +549,8 @@ public class NotificationTestHelper {
mock(MetricsLogger.class), mock(MetricsLogger.class),
mock(SmartReplyConstants.class), mock(SmartReplyConstants.class),
mock(SmartReplyController.class), mock(SmartReplyController.class),
mFeatureFlags); mFeatureFlags,
mock(IStatusBarService.class));
row.setAboveShelfChangedListener(aboveShelf -> { }); row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags); mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);