Enforcing a maximum depth on nested RemoteViews calls
An unchecked read from parcel can lead to StackOverflowError Test: am instrument -w -e class android.widget.RemoteViewsTest com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner Bug: 26755067 Change-Id: I36ea253846d5c823899097821270dcfca2472b65
This commit is contained in:
@@ -42,11 +42,13 @@ import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.StrictMode;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
@@ -91,6 +93,12 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
*/
|
||||
static final String EXTRA_REMOTEADAPTER_APPWIDGET_ID = "remoteAdapterAppWidgetId";
|
||||
|
||||
/**
|
||||
* Maximum depth of nested views calls from {@link #addView(int, RemoteViews)} and
|
||||
* {@link #RemoteViews(RemoteViews, RemoteViews)}.
|
||||
*/
|
||||
private static final int MAX_NESTED_VIEWS = 10;
|
||||
|
||||
/**
|
||||
* Application that hosts the remote views.
|
||||
*
|
||||
@@ -1538,11 +1546,11 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
}
|
||||
|
||||
ViewGroupAction(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info) {
|
||||
ViewGroupAction(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, int depth) {
|
||||
viewId = parcel.readInt();
|
||||
boolean nestedViewsNull = parcel.readInt() == 0;
|
||||
if (!nestedViewsNull) {
|
||||
nestedViews = new RemoteViews(parcel, bitmapCache, info);
|
||||
nestedViews = new RemoteViews(parcel, bitmapCache, info, depth);
|
||||
} else {
|
||||
nestedViews = null;
|
||||
}
|
||||
@@ -2209,10 +2217,16 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
* @param parcel
|
||||
*/
|
||||
public RemoteViews(Parcel parcel) {
|
||||
this(parcel, null, null);
|
||||
this(parcel, null, null, 0);
|
||||
}
|
||||
|
||||
private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info) {
|
||||
private RemoteViews(Parcel parcel, BitmapCache bitmapCache, ApplicationInfo info, int depth) {
|
||||
if (depth > MAX_NESTED_VIEWS
|
||||
&& (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)) {
|
||||
throw new IllegalArgumentException("Too many nested views.");
|
||||
}
|
||||
depth++;
|
||||
|
||||
int mode = parcel.readInt();
|
||||
|
||||
// We only store a bitmap cache in the root of the RemoteViews.
|
||||
@@ -2245,7 +2259,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
mActions.add(new ReflectionAction(parcel));
|
||||
break;
|
||||
case ViewGroupAction.TAG:
|
||||
mActions.add(new ViewGroupAction(parcel, mBitmapCache, mApplication));
|
||||
mActions.add(new ViewGroupAction(parcel, mBitmapCache, mApplication,
|
||||
depth));
|
||||
break;
|
||||
case ReflectionActionWithoutParams.TAG:
|
||||
mActions.add(new ReflectionActionWithoutParams(parcel));
|
||||
@@ -2293,8 +2308,8 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
}
|
||||
} else {
|
||||
// MODE_HAS_LANDSCAPE_AND_PORTRAIT
|
||||
mLandscape = new RemoteViews(parcel, mBitmapCache, info);
|
||||
mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication);
|
||||
mLandscape = new RemoteViews(parcel, mBitmapCache, info, depth);
|
||||
mPortrait = new RemoteViews(parcel, mBitmapCache, mLandscape.mApplication, depth);
|
||||
mApplication = mPortrait.mApplication;
|
||||
mLayoutId = mPortrait.getLayoutId();
|
||||
}
|
||||
@@ -2318,7 +2333,7 @@ public class RemoteViews implements Parcelable, Filter {
|
||||
p.setDataPosition(0);
|
||||
mIsRoot = true;
|
||||
|
||||
RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication);
|
||||
RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication, 0);
|
||||
rv.mIsRoot = true;
|
||||
|
||||
p.recycle();
|
||||
|
||||
@@ -179,13 +179,8 @@ public class RemoteViewsTest {
|
||||
ViewAppliedListener listener = new ViewAppliedListener();
|
||||
views.applyAsync(mContext, mContainer, AsyncTask.THREAD_POOL_EXECUTOR, listener);
|
||||
|
||||
boolean exceptionThrown = false;
|
||||
try {
|
||||
listener.waitAndGetView();
|
||||
} catch (Exception e) {
|
||||
exceptionThrown = true;
|
||||
}
|
||||
assertTrue(exceptionThrown);
|
||||
exception.expect(Exception.class);
|
||||
listener.waitAndGetView();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -332,4 +327,43 @@ public class RemoteViewsTest {
|
||||
return mView;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedAddViews() {
|
||||
RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
parent.addView(R.id.layout, views);
|
||||
views = parent;
|
||||
}
|
||||
views.clone();
|
||||
|
||||
views = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
for (int i = 0; i < 11; i++) {
|
||||
RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
parent.addView(R.id.layout, views);
|
||||
views = parent;
|
||||
}
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
views.clone();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedLandscapeViews() {
|
||||
RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
views = new RemoteViews(views,
|
||||
new RemoteViews(mPackage, R.layout.remote_views_test));
|
||||
}
|
||||
views.clone();
|
||||
|
||||
views = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
for (int i = 0; i < 11; i++) {
|
||||
RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
|
||||
parent.addView(R.id.layout, views);
|
||||
views = parent;
|
||||
}
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
views.clone();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user