• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 import static android.os.BundleMerger.STRATEGY_ARRAY_APPEND;
20 import static android.os.BundleMerger.STRATEGY_ARRAY_LIST_APPEND;
21 import static android.os.BundleMerger.STRATEGY_ARRAY_UNION;
22 import static android.os.BundleMerger.STRATEGY_BOOLEAN_AND;
23 import static android.os.BundleMerger.STRATEGY_BOOLEAN_OR;
24 import static android.os.BundleMerger.STRATEGY_COMPARABLE_MAX;
25 import static android.os.BundleMerger.STRATEGY_COMPARABLE_MIN;
26 import static android.os.BundleMerger.STRATEGY_FIRST;
27 import static android.os.BundleMerger.STRATEGY_LAST;
28 import static android.os.BundleMerger.STRATEGY_NUMBER_ADD;
29 import static android.os.BundleMerger.STRATEGY_NUMBER_INCREMENT_FIRST;
30 import static android.os.BundleMerger.STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD;
31 import static android.os.BundleMerger.STRATEGY_REJECT;
32 import static android.os.BundleMerger.STRATEGY_STRING_APPEND;
33 import static android.os.BundleMerger.merge;
34 
35 import static org.junit.Assert.assertArrayEquals;
36 import static org.junit.Assert.assertEquals;
37 import static org.junit.Assert.assertThrows;
38 
39 import android.content.Intent;
40 import android.net.Uri;
41 
42 import androidx.test.filters.SmallTest;
43 
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.junit.runners.JUnit4;
47 
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.Set;
51 
52 @SmallTest
53 @RunWith(JUnit4.class)
54 public class BundleMergerTest {
55     /**
56      * Strategies are only applied when there is an actual conflict; in the
57      * absence of conflict we pick whichever value is defined.
58      */
59     @Test
testNoConflict()60     public void testNoConflict() throws Exception {
61         for (int strategy = Byte.MIN_VALUE; strategy < Byte.MAX_VALUE; strategy++) {
62             assertEquals(null, merge(strategy, null, null));
63             assertEquals(10, merge(strategy, 10, null));
64             assertEquals(20, merge(strategy, null, 20));
65         }
66     }
67 
68     /**
69      * Strategies are only applied to identical data types; if there are mixed
70      * types we always reject the two conflicting values.
71      */
72     @Test
testMixedTypes()73     public void testMixedTypes() throws Exception {
74         for (int strategy = Byte.MIN_VALUE; strategy < Byte.MAX_VALUE; strategy++) {
75             final int finalStrategy = strategy;
76             assertThrows(Exception.class, () -> {
77                 merge(finalStrategy, 10, "foo");
78             });
79             assertThrows(Exception.class, () -> {
80                 merge(finalStrategy, List.of("foo"), "bar");
81             });
82             assertThrows(Exception.class, () -> {
83                 merge(finalStrategy, new String[] { "foo" }, "bar");
84             });
85             assertThrows(Exception.class, () -> {
86                 merge(finalStrategy, Integer.valueOf(10), Long.valueOf(10));
87             });
88         }
89     }
90 
91     @Test
testStrategyReject()92     public void testStrategyReject() throws Exception {
93         assertEquals(null, merge(STRATEGY_REJECT, 10, 20));
94 
95         // Identical values aren't technically a conflict, so they're passed
96         // through without being rejected
97         assertEquals(10, merge(STRATEGY_REJECT, 10, 10));
98         assertArrayEquals(new int[] {10},
99                 (int[]) merge(STRATEGY_REJECT, new int[] {10}, new int[] {10}));
100     }
101 
102     @Test
testStrategyFirst()103     public void testStrategyFirst() throws Exception {
104         assertEquals(10, merge(STRATEGY_FIRST, 10, 20));
105     }
106 
107     @Test
testStrategyLast()108     public void testStrategyLast() throws Exception {
109         assertEquals(20, merge(STRATEGY_LAST, 10, 20));
110     }
111 
112     @Test
testStrategyComparableMin()113     public void testStrategyComparableMin() throws Exception {
114         assertEquals(10, merge(STRATEGY_COMPARABLE_MIN, 10, 20));
115         assertEquals(10, merge(STRATEGY_COMPARABLE_MIN, 20, 10));
116         assertEquals("a", merge(STRATEGY_COMPARABLE_MIN, "a", "z"));
117         assertEquals("a", merge(STRATEGY_COMPARABLE_MIN, "z", "a"));
118 
119         assertThrows(Exception.class, () -> {
120             merge(STRATEGY_COMPARABLE_MIN, new Binder(), new Binder());
121         });
122     }
123 
124     @Test
testStrategyComparableMax()125     public void testStrategyComparableMax() throws Exception {
126         assertEquals(20, merge(STRATEGY_COMPARABLE_MAX, 10, 20));
127         assertEquals(20, merge(STRATEGY_COMPARABLE_MAX, 20, 10));
128         assertEquals("z", merge(STRATEGY_COMPARABLE_MAX, "a", "z"));
129         assertEquals("z", merge(STRATEGY_COMPARABLE_MAX, "z", "a"));
130 
131         assertThrows(Exception.class, () -> {
132             merge(STRATEGY_COMPARABLE_MAX, new Binder(), new Binder());
133         });
134     }
135 
136     @Test
testStrategyNumberAdd()137     public void testStrategyNumberAdd() throws Exception {
138         assertEquals(30, merge(STRATEGY_NUMBER_ADD, 10, 20));
139         assertEquals(30, merge(STRATEGY_NUMBER_ADD, 20, 10));
140         assertEquals(30L, merge(STRATEGY_NUMBER_ADD, 10L, 20L));
141         assertEquals(30L, merge(STRATEGY_NUMBER_ADD, 20L, 10L));
142 
143         assertThrows(Exception.class, () -> {
144             merge(STRATEGY_NUMBER_ADD, new Binder(), new Binder());
145         });
146     }
147 
148     @Test
testStrategyNumberIncrementFirst()149     public void testStrategyNumberIncrementFirst() throws Exception {
150         assertEquals(11, merge(STRATEGY_NUMBER_INCREMENT_FIRST, 10, 20));
151         assertEquals(21, merge(STRATEGY_NUMBER_INCREMENT_FIRST, 20, 10));
152         assertEquals(11L, merge(STRATEGY_NUMBER_INCREMENT_FIRST, 10L, 20L));
153         assertEquals(21L, merge(STRATEGY_NUMBER_INCREMENT_FIRST, 20L, 10L));
154     }
155 
156     @Test
testStrategyNumberIncrementFirstAndAdd()157     public void testStrategyNumberIncrementFirstAndAdd() throws Exception {
158         assertEquals(31, merge(STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD, 10, 20));
159         assertEquals(31, merge(STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD, 20, 10));
160         assertEquals(31L, merge(STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD, 10L, 20L));
161         assertEquals(31L, merge(STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD, 20L, 10L));
162     }
163 
164     @Test
testStrategyBooleanAnd()165     public void testStrategyBooleanAnd() throws Exception {
166         assertEquals(false, merge(STRATEGY_BOOLEAN_AND, false, false));
167         assertEquals(false, merge(STRATEGY_BOOLEAN_AND, true, false));
168         assertEquals(false, merge(STRATEGY_BOOLEAN_AND, false, true));
169         assertEquals(true, merge(STRATEGY_BOOLEAN_AND, true, true));
170 
171         assertThrows(Exception.class, () -> {
172             merge(STRATEGY_BOOLEAN_AND, "True!", "False?");
173         });
174     }
175 
176     @Test
testStrategyBooleanOr()177     public void testStrategyBooleanOr() throws Exception {
178         assertEquals(false, merge(STRATEGY_BOOLEAN_OR, false, false));
179         assertEquals(true, merge(STRATEGY_BOOLEAN_OR, true, false));
180         assertEquals(true, merge(STRATEGY_BOOLEAN_OR, false, true));
181         assertEquals(true, merge(STRATEGY_BOOLEAN_OR, true, true));
182 
183         assertThrows(Exception.class, () -> {
184             merge(STRATEGY_BOOLEAN_OR, "True!", "False?");
185         });
186     }
187 
188     @Test
testStrategyArrayAppend()189     public void testStrategyArrayAppend() throws Exception {
190         assertArrayEquals(new int[] {},
191                 (int[]) merge(STRATEGY_ARRAY_APPEND, new int[] {}, new int[] {}));
192         assertArrayEquals(new int[] {10},
193                 (int[]) merge(STRATEGY_ARRAY_APPEND, new int[] {10}, new int[] {}));
194         assertArrayEquals(new int[] {20},
195                 (int[]) merge(STRATEGY_ARRAY_APPEND, new int[] {}, new int[] {20}));
196         assertArrayEquals(new int[] {10, 20},
197                 (int[]) merge(STRATEGY_ARRAY_APPEND, new int[] {10}, new int[] {20}));
198         assertArrayEquals(new int[] {10, 30, 20, 40},
199                 (int[]) merge(STRATEGY_ARRAY_APPEND, new int[] {10, 30}, new int[] {20, 40}));
200         assertArrayEquals(new String[] {"a", "b"},
201                 (String[]) merge(STRATEGY_ARRAY_APPEND, new String[] {"a"}, new String[] {"b"}));
202 
203         assertThrows(Exception.class, () -> {
204             merge(STRATEGY_ARRAY_APPEND, 10, 20);
205         });
206     }
207 
208     @Test
testStrategyArrayUnion()209     public void testStrategyArrayUnion() throws Exception {
210         assertArrayEquals(new int[] {},
211                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {}, new int[] {}));
212         assertArrayEquals(new int[] {10},
213                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {10}, new int[] {}));
214         assertArrayEquals(new int[] {20},
215                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {}, new int[] {20}));
216         assertArrayEquals(new int[] {10, 20},
217                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {10}, new int[] {20}));
218         assertArrayEquals(new int[] {10, 20, 30, 40},
219                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {10, 30}, new int[] {20, 40}));
220         assertArrayEquals(new int[] {10, 20, 30},
221                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {10, 30}, new int[] {10, 20}));
222         assertArrayEquals(new int[] {10, 20},
223                 (int[]) merge(STRATEGY_ARRAY_UNION, new int[] {10, 20}, new int[] {20}));
224         assertArrayEquals(new String[] {"a", "b"},
225                 (String[]) merge(STRATEGY_ARRAY_UNION, new String[] {"a"}, new String[] {"b"}));
226         assertArrayEquals(new String[] {"a", "b", "c"},
227                 (String[]) merge(STRATEGY_ARRAY_UNION, new String[] {"a", "b"},
228                         new String[] {"b", "c"}));
229 
230         assertThrows(Exception.class, () -> {
231             merge(STRATEGY_ARRAY_UNION, 10, 20);
232         });
233     }
234 
235     @Test
testStrategyArrayListAppend()236     public void testStrategyArrayListAppend() throws Exception {
237         assertEquals(arrayListOf(),
238                 merge(STRATEGY_ARRAY_LIST_APPEND, arrayListOf(), arrayListOf()));
239         assertEquals(arrayListOf(10),
240                 merge(STRATEGY_ARRAY_LIST_APPEND, arrayListOf(10), arrayListOf()));
241         assertEquals(arrayListOf(20),
242                 merge(STRATEGY_ARRAY_LIST_APPEND, arrayListOf(), arrayListOf(20)));
243         assertEquals(arrayListOf(10, 20),
244                 merge(STRATEGY_ARRAY_LIST_APPEND, arrayListOf(10), arrayListOf(20)));
245         assertEquals(arrayListOf(10, 30, 20, 40),
246                 merge(STRATEGY_ARRAY_LIST_APPEND, arrayListOf(10, 30), arrayListOf(20, 40)));
247         assertEquals(arrayListOf("a", "b"),
248                 merge(STRATEGY_ARRAY_LIST_APPEND, arrayListOf("a"), arrayListOf("b")));
249 
250         assertThrows(Exception.class, () -> {
251             merge(STRATEGY_ARRAY_LIST_APPEND, 10, 20);
252         });
253     }
254 
255     @Test
testStrategyStringAppend()256     public void testStrategyStringAppend() throws Exception {
257         assertEquals("ab", merge(STRATEGY_STRING_APPEND, "a", "b"));
258         assertEquals("abc", merge(STRATEGY_STRING_APPEND, "a", "bc"));
259         assertEquals("abc", merge(STRATEGY_STRING_APPEND, "ab", "c"));
260         assertEquals("a,b,c,", merge(STRATEGY_STRING_APPEND, "a,", "b,c,"));
261 
262         assertThrows(Exception.class, () -> {
263             merge(STRATEGY_STRING_APPEND, 10, 20);
264         });
265     }
266 
267     @Test
testSetDefaultMergeStrategy()268     public void testSetDefaultMergeStrategy() throws Exception {
269         final BundleMerger merger = new BundleMerger();
270         merger.setDefaultMergeStrategy(STRATEGY_FIRST);
271         merger.setMergeStrategy(Intent.EXTRA_INDEX, STRATEGY_COMPARABLE_MAX);
272 
273         Bundle a = new Bundle();
274         a.putString(Intent.EXTRA_SUBJECT, "SubjectA");
275         a.putInt(Intent.EXTRA_INDEX, 10);
276 
277         Bundle b = new Bundle();
278         b.putString(Intent.EXTRA_SUBJECT, "SubjectB");
279         b.putInt(Intent.EXTRA_INDEX, 20);
280 
281         Bundle ab = merger.merge(a, b);
282         assertEquals("SubjectA", ab.getString(Intent.EXTRA_SUBJECT));
283         assertEquals(20, ab.getInt(Intent.EXTRA_INDEX));
284 
285         Bundle ba = merger.merge(b, a);
286         assertEquals("SubjectB", ba.getString(Intent.EXTRA_SUBJECT));
287         assertEquals(20, ba.getInt(Intent.EXTRA_INDEX));
288     }
289 
290     @Test
testMerge_Simple()291     public void testMerge_Simple() throws Exception {
292         final BundleMerger merger = new BundleMerger();
293         final Bundle probe = new Bundle();
294         probe.putInt(Intent.EXTRA_INDEX, 42);
295 
296         assertEquals(null, merger.merge(null, null));
297         assertEquals(probe.keySet(), merger.merge(probe, null).keySet());
298         assertEquals(probe.keySet(), merger.merge(null, probe).keySet());
299         assertEquals(probe.keySet(), merger.merge(probe, probe).keySet());
300     }
301 
302     /**
303      * Verify that we can merge parcelables present in the base classpath, since
304      * everyone on the device will be able to unpack them.
305      */
306     @Test
testMerge_Parcelable_BCP()307     public void testMerge_Parcelable_BCP() throws Exception {
308         final BundleMerger merger = new BundleMerger();
309         merger.setMergeStrategy(Intent.EXTRA_STREAM, STRATEGY_COMPARABLE_MIN);
310 
311         Bundle a = new Bundle();
312         a.putParcelable(Intent.EXTRA_STREAM, Uri.parse("http://example.com"));
313         a = parcelAndUnparcel(a);
314 
315         Bundle b = new Bundle();
316         b.putParcelable(Intent.EXTRA_STREAM, Uri.parse("http://example.net"));
317         b = parcelAndUnparcel(b);
318 
319         assertEquals(Uri.parse("http://example.com"),
320                 merger.merge(a, b).getParcelable(Intent.EXTRA_STREAM, Uri.class));
321         assertEquals(Uri.parse("http://example.com"),
322                 merger.merge(b, a).getParcelable(Intent.EXTRA_STREAM, Uri.class));
323     }
324 
325     /**
326      * Verify that we tiptoe around custom parcelables while still merging other
327      * known data types. Custom parcelables aren't in the base classpath, so not
328      * everyone on the device will be able to unpack them.
329      */
330     @Test
testMerge_Parcelable_Custom()331     public void testMerge_Parcelable_Custom() throws Exception {
332         final BundleMerger merger = new BundleMerger();
333         merger.setMergeStrategy(Intent.EXTRA_INDEX, STRATEGY_NUMBER_ADD);
334 
335         Bundle a = new Bundle();
336         a.putInt(Intent.EXTRA_INDEX, 10);
337         a.putString(Intent.EXTRA_CC, "foo@bar.com");
338         a.putParcelable(Intent.EXTRA_SUBJECT, new ExplodingParcelable());
339         a = parcelAndUnparcel(a);
340 
341         Bundle b = new Bundle();
342         b.putInt(Intent.EXTRA_INDEX, 20);
343         a.putString(Intent.EXTRA_BCC, "foo@baz.com");
344         b.putParcelable(Intent.EXTRA_STREAM, new ExplodingParcelable());
345         b = parcelAndUnparcel(b);
346 
347         Bundle ab = merger.merge(a, b);
348         assertEquals(Set.of(Intent.EXTRA_INDEX, Intent.EXTRA_CC, Intent.EXTRA_BCC,
349                 Intent.EXTRA_SUBJECT, Intent.EXTRA_STREAM), ab.keySet());
350         assertEquals(30, ab.getInt(Intent.EXTRA_INDEX));
351         assertEquals("foo@bar.com", ab.getString(Intent.EXTRA_CC));
352         assertEquals("foo@baz.com", ab.getString(Intent.EXTRA_BCC));
353 
354         // And finally, make sure that if we try unpacking one of our custom
355         // values that we actually explode
356         assertThrows(BadParcelableException.class, () -> {
357             ab.getParcelable(Intent.EXTRA_SUBJECT, ExplodingParcelable.class);
358         });
359         assertThrows(BadParcelableException.class, () -> {
360             ab.getParcelable(Intent.EXTRA_STREAM, ExplodingParcelable.class);
361         });
362     }
363 
364     @Test
testMerge_PackageChanged()365     public void testMerge_PackageChanged() throws Exception {
366         final BundleMerger merger = new BundleMerger();
367         merger.setMergeStrategy(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, STRATEGY_ARRAY_APPEND);
368 
369         final Bundle first = new Bundle();
370         first.putInt(Intent.EXTRA_UID, 10001);
371         first.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, new String[] {
372                 "com.example.Foo",
373         });
374 
375         final Bundle second = new Bundle();
376         second.putInt(Intent.EXTRA_UID, 10001);
377         second.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, new String[] {
378                 "com.example.Bar",
379                 "com.example.Baz",
380         });
381 
382         final Bundle res = merger.merge(first, second);
383         assertEquals(10001, res.getInt(Intent.EXTRA_UID));
384         assertArrayEquals(new String[] {
385                 "com.example.Foo", "com.example.Bar", "com.example.Baz",
386         }, res.getStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
387     }
388 
389     /**
390      * Each event in isolation reports "zero events dropped", but if we need to
391      * merge them together, then we start incrementing.
392      */
393     @Test
testMerge_DropBox()394     public void testMerge_DropBox() throws Exception {
395         final BundleMerger merger = new BundleMerger();
396         merger.setMergeStrategy(DropBoxManager.EXTRA_TIME,
397                 STRATEGY_COMPARABLE_MAX);
398         merger.setMergeStrategy(DropBoxManager.EXTRA_DROPPED_COUNT,
399                 STRATEGY_NUMBER_INCREMENT_FIRST_AND_ADD);
400 
401         final long now = System.currentTimeMillis();
402         final Bundle a = new Bundle();
403         a.putString(DropBoxManager.EXTRA_TAG, "system_server_strictmode");
404         a.putLong(DropBoxManager.EXTRA_TIME, now);
405         a.putInt(DropBoxManager.EXTRA_DROPPED_COUNT, 0);
406 
407         final Bundle b = new Bundle();
408         b.putString(DropBoxManager.EXTRA_TAG, "system_server_strictmode");
409         b.putLong(DropBoxManager.EXTRA_TIME, now + 1000);
410         b.putInt(DropBoxManager.EXTRA_DROPPED_COUNT, 0);
411 
412         final Bundle c = new Bundle();
413         c.putString(DropBoxManager.EXTRA_TAG, "system_server_strictmode");
414         c.putLong(DropBoxManager.EXTRA_TIME, now + 2000);
415         c.putInt(DropBoxManager.EXTRA_DROPPED_COUNT, 0);
416 
417         final Bundle d = new Bundle();
418         d.putString(DropBoxManager.EXTRA_TAG, "system_server_strictmode");
419         d.putLong(DropBoxManager.EXTRA_TIME, now + 3000);
420         d.putInt(DropBoxManager.EXTRA_DROPPED_COUNT, 5);
421 
422         final Bundle ab = merger.merge(a, b);
423         assertEquals("system_server_strictmode", ab.getString(DropBoxManager.EXTRA_TAG));
424         assertEquals(now + 1000, ab.getLong(DropBoxManager.EXTRA_TIME));
425         assertEquals(1, ab.getInt(DropBoxManager.EXTRA_DROPPED_COUNT));
426 
427         final Bundle abc = merger.merge(ab, c);
428         assertEquals("system_server_strictmode", abc.getString(DropBoxManager.EXTRA_TAG));
429         assertEquals(now + 2000, abc.getLong(DropBoxManager.EXTRA_TIME));
430         assertEquals(2, abc.getInt(DropBoxManager.EXTRA_DROPPED_COUNT));
431 
432         final Bundle abcd = merger.merge(abc, d);
433         assertEquals("system_server_strictmode", abcd.getString(DropBoxManager.EXTRA_TAG));
434         assertEquals(now + 3000, abcd.getLong(DropBoxManager.EXTRA_TIME));
435         assertEquals(8, abcd.getInt(DropBoxManager.EXTRA_DROPPED_COUNT));
436     }
437 
arrayListOf(Object... values)438     private static ArrayList<Object> arrayListOf(Object... values) {
439         final ArrayList<Object> res = new ArrayList<>(values.length);
440         for (Object value : values) {
441             res.add(value);
442         }
443         return res;
444     }
445 
parcelAndUnparcel(Bundle input)446     private static Bundle parcelAndUnparcel(Bundle input) {
447         final Parcel parcel = Parcel.obtain();
448         try {
449             input.writeToParcel(parcel, 0);
450             parcel.setDataPosition(0);
451             return Bundle.CREATOR.createFromParcel(parcel);
452         } finally {
453             parcel.recycle();
454         }
455     }
456 
457     /**
458      * Object that only offers to parcel itself; if something tries unparceling
459      * it, it will "explode" by throwing an exception.
460      * <p>
461      * Useful for verifying interactions that must leave unknown data in a
462      * parceled state.
463      */
464     public static class ExplodingParcelable implements Parcelable {
ExplodingParcelable()465         public ExplodingParcelable() {
466         }
467 
468         @Override
describeContents()469         public int describeContents() {
470             return 0;
471         }
472 
473         @Override
writeToParcel(Parcel out, int flags)474         public void writeToParcel(Parcel out, int flags) {
475             out.writeInt(42);
476         }
477 
478         public static final Creator<ExplodingParcelable> CREATOR =
479                 new Creator<ExplodingParcelable>() {
480                     @Override
481                     public ExplodingParcelable createFromParcel(Parcel in) {
482                         throw new BadParcelableException("exploding!");
483                     }
484 
485                     @Override
486                     public ExplodingParcelable[] newArray(int size) {
487                         throw new BadParcelableException("exploding!");
488                     }
489                 };
490     }
491 }
492