• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertThrows;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.platform.test.annotations.Presubmit;
27 import android.platform.test.ravenwood.RavenwoodRule;
28 import android.util.Log;
29 
30 import androidx.test.ext.junit.runners.AndroidJUnit4;
31 
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 
36 import java.util.ArrayList;
37 
38 @Presubmit
39 @RunWith(AndroidJUnit4.class)
40 public class ParcelTest {
41     @Rule
42     public final RavenwoodRule mRavenwood = new RavenwoodRule();
43 
44     private static final int WORK_SOURCE_1 = 1000;
45     private static final int WORK_SOURCE_2 = 1002;
46     private static final String INTERFACE_TOKEN_1 = "IBinder interface token";
47     private static final String INTERFACE_TOKEN_2 = "Another IBinder interface token";
48 
49     @Test
testIsForRpc()50     public void testIsForRpc() {
51         Parcel p = Parcel.obtain();
52         assertEquals(false, p.isForRpc());
53         p.recycle();
54     }
55 
56     @Test
testCallingWorkSourceUidAfterWrite()57     public void testCallingWorkSourceUidAfterWrite() {
58         Parcel p = Parcel.obtain();
59         // Method does not throw if replaceCallingWorkSourceUid is called before requests headers
60         // are added.
61         assertEquals(false, p.replaceCallingWorkSourceUid(WORK_SOURCE_1));
62         assertEquals(Binder.UNSET_WORKSOURCE, p.readCallingWorkSourceUid());
63 
64         // WorkSource can be updated.
65         p.writeInterfaceToken(INTERFACE_TOKEN_1);
66         assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2));
67         assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid());
68 
69         // WorkSource can be updated to unset value.
70         assertEquals(true, p.replaceCallingWorkSourceUid(Binder.UNSET_WORKSOURCE));
71         assertEquals(Binder.UNSET_WORKSOURCE, p.readCallingWorkSourceUid());
72 
73         p.recycle();
74     }
75 
76     @Test
testCallingWorkSourceUidAfterEnforce()77     public void testCallingWorkSourceUidAfterEnforce() {
78         Parcel p = Parcel.obtain();
79         p.writeInterfaceToken(INTERFACE_TOKEN_1);
80         assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_1));
81         p.setDataPosition(0);
82 
83         p.enforceInterface(INTERFACE_TOKEN_1);
84         assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid());
85 
86         // WorkSource can be updated.
87         assertEquals(true, p.replaceCallingWorkSourceUid(WORK_SOURCE_2));
88         assertEquals(WORK_SOURCE_2, p.readCallingWorkSourceUid());
89 
90         p.recycle();
91     }
92 
93     @Test
testParcelWithMultipleHeaders()94     public void testParcelWithMultipleHeaders() {
95         Parcel p = Parcel.obtain();
96         Binder.setCallingWorkSourceUid(WORK_SOURCE_1);
97         p.writeInterfaceToken(INTERFACE_TOKEN_1);
98         Binder.setCallingWorkSourceUid(WORK_SOURCE_2);
99         p.writeInterfaceToken(INTERFACE_TOKEN_2);
100         p.setDataPosition(0);
101 
102         // WorkSource is from the first header.
103         p.enforceInterface(INTERFACE_TOKEN_1);
104         assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid());
105         p.enforceInterface(INTERFACE_TOKEN_2);
106         assertEquals(WORK_SOURCE_1, p.readCallingWorkSourceUid());
107 
108         p.recycle();
109     }
110 
111     /**
112      * Verify that writing/reading UTF-8 and UTF-16 strings works well.
113      */
114     @Test
testStrings()115     public void testStrings() {
116         final String[] strings = {
117                 null, "", "abc\0def", "com.example.typical_package_name",
118                 "從不喜歡孤單一個 - 蘇永康/吳雨霏", "example"
119         };
120 
121         final Parcel p = Parcel.obtain();
122         for (String string : strings) {
123             p.writeString8(string);
124             p.writeString16(string);
125         }
126 
127         p.setDataPosition(0);
128         for (String string : strings) {
129             assertEquals(string, p.readString8());
130             assertEquals(string, p.readString16());
131         }
132     }
133 
134     @Test
testCompareDataInRange_whenSameData()135     public void testCompareDataInRange_whenSameData() {
136         Parcel pA = Parcel.obtain();
137         int iA = pA.dataPosition();
138         pA.writeInt(13);
139         pA.writeString("Tiramisu");
140         int length = pA.dataPosition() - iA;
141         Parcel pB = Parcel.obtain();
142         pB.writeString("Prefix");
143         int iB = pB.dataPosition();
144         pB.writeInt(13);
145         pB.writeString("Tiramisu");
146 
147         assertTrue(Parcel.compareData(pA, iA, pB, iB, length));
148     }
149 
150     @Test
testCompareDataInRange_whenSameDataWithBinder()151     public void testCompareDataInRange_whenSameDataWithBinder() {
152         Binder binder = new Binder();
153         Parcel pA = Parcel.obtain();
154         int iA = pA.dataPosition();
155         pA.writeInt(13);
156         pA.writeStrongBinder(binder);
157         pA.writeString("Tiramisu");
158         int length = pA.dataPosition() - iA;
159         Parcel pB = Parcel.obtain();
160         pB.writeString("Prefix");
161         int iB = pB.dataPosition();
162         pB.writeInt(13);
163         pB.writeStrongBinder(binder);
164         pB.writeString("Tiramisu");
165 
166         assertTrue(Parcel.compareData(pA, iA, pB, iB, length));
167     }
168 
169     @Test
testCompareDataInRange_whenDifferentData()170     public void testCompareDataInRange_whenDifferentData() {
171         Parcel pA = Parcel.obtain();
172         int iA = pA.dataPosition();
173         pA.writeInt(13);
174         pA.writeString("Tiramisu");
175         int length = pA.dataPosition() - iA;
176         Parcel pB = Parcel.obtain();
177         int iB = pB.dataPosition();
178         pB.writeString("Prefix");
179         pB.writeInt(13);
180         pB.writeString("Tiramisu");
181 
182         assertFalse(Parcel.compareData(pA, iA, pB, iB, length));
183     }
184 
185     @Test
testCompareDataInRange_whenLimitOutOfBounds_throws()186     public void testCompareDataInRange_whenLimitOutOfBounds_throws() {
187         Parcel pA = Parcel.obtain();
188         int iA = pA.dataPosition();
189         pA.writeInt(12);
190         pA.writeString("Tiramisu");
191         int length = pA.dataPosition() - iA;
192         Parcel pB = Parcel.obtain();
193         pB.writeString("Prefix");
194         int iB = pB.dataPosition();
195         pB.writeInt(13);
196         pB.writeString("Tiramisu");
197         pB.writeInt(-1);
198 
199         assertThrows(IllegalArgumentException.class,
200                 () -> Parcel.compareData(pA, iA + length, pB, iB, 1));
201         assertThrows(IllegalArgumentException.class,
202                 () -> Parcel.compareData(pA, iA, pB, pB.dataSize(), 1));
203         assertThrows(IllegalArgumentException.class,
204                 () -> Parcel.compareData(pA, iA, pB, iB, length + 1));
205         assertThrows(IllegalArgumentException.class,
206                 () -> Parcel.compareData(pA, iA + length + 1, pB, iB, 0));
207         assertThrows(IllegalArgumentException.class,
208                 () -> Parcel.compareData(pA, iA, pB, iB + pB.dataSize() + 1, 0));
209     }
210 
211     @Test
testCompareDataInRange_whenLengthZero()212     public void testCompareDataInRange_whenLengthZero() {
213         Parcel pA = Parcel.obtain();
214         int iA = pA.dataPosition();
215         pA.writeInt(12);
216         pA.writeString("Tiramisu");
217         int length = pA.dataPosition() - iA;
218         Parcel pB = Parcel.obtain();
219         pB.writeString("Prefix");
220         int iB = pB.dataPosition();
221         pB.writeInt(13);
222         pB.writeString("Tiramisu");
223 
224         assertTrue(Parcel.compareData(pA, 0, pB, iB, 0));
225         assertTrue(Parcel.compareData(pA, iA + length, pB, iB, 0));
226         assertTrue(Parcel.compareData(pA, iA, pB, pB.dataSize(), 0));
227     }
228 
229     @Test
testCompareDataInRange_whenNegativeLength_throws()230     public void testCompareDataInRange_whenNegativeLength_throws() {
231         Parcel pA = Parcel.obtain();
232         int iA = pA.dataPosition();
233         pA.writeInt(12);
234         pA.writeString("Tiramisu");
235         Parcel pB = Parcel.obtain();
236         pB.writeString("Prefix");
237         int iB = pB.dataPosition();
238         pB.writeInt(13);
239         pB.writeString("Tiramisu");
240 
241         assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, iA, pB, iB, -1));
242     }
243 
244     @Test
testCompareDataInRange_whenNegativeOffset_throws()245     public void testCompareDataInRange_whenNegativeOffset_throws() {
246         Parcel pA = Parcel.obtain();
247         int iA = pA.dataPosition();
248         pA.writeInt(12);
249         pA.writeString("Tiramisu");
250         Parcel pB = Parcel.obtain();
251         pB.writeString("Prefix");
252         int iB = pB.dataPosition();
253         pB.writeInt(13);
254         pB.writeString("Tiramisu");
255 
256         assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, -1, pB, iB, 0));
257         assertThrows(IllegalArgumentException.class, () -> Parcel.compareData(pA, 0, pB, -1, 0));
258     }
259 
260     /***
261      * Tests for b/205282403
262      * This test checks if allocations made over limit of 1MB for primitive types
263      * and 1M length for complex objects are not allowed.
264      */
265     @Test
testAllocationsOverLimit_whenOverLimit_throws()266     public void testAllocationsOverLimit_whenOverLimit_throws() {
267         Binder.setIsDirectlyHandlingTransactionOverride(true);
268         Parcel p = Parcel.obtain();
269         p.setDataPosition(0);
270         p.writeInt(Integer.MAX_VALUE);
271 
272         p.setDataPosition(0);
273         assertThrows(BadParcelableException.class, () ->p.createBooleanArray());
274 
275         p.setDataPosition(0);
276         assertThrows(BadParcelableException.class, () ->p.createCharArray());
277 
278         p.setDataPosition(0);
279         assertThrows(BadParcelableException.class, () ->p.createIntArray());
280 
281         p.setDataPosition(0);
282         assertThrows(BadParcelableException.class, () ->p.createLongArray());
283 
284         p.setDataPosition(0);
285         assertThrows(BadParcelableException.class, () ->p.createBinderArray());
286 
287         int[] dimensions = new int[]{Integer.MAX_VALUE, 100, 100};
288         p.setDataPosition(0);
289         assertThrows(BadParcelableException.class,
290                 () -> p.createFixedArray(int[][][].class, dimensions));
291 
292         p.setDataPosition(0);
293         assertThrows(BadParcelableException.class,
294                 () -> p.createFixedArray(String[][][].class, dimensions));
295 
296         p.setDataPosition(0);
297         assertThrows(BadParcelableException.class,
298                 () -> p.createFixedArray(IBinder[][][].class, dimensions));
299 
300         p.recycle();
301         Binder.setIsDirectlyHandlingTransactionOverride(false);
302     }
303 
304     /***
305      * Tests for b/205282403
306      * This test checks if allocations made under limit of 1MB for primitive types
307      * and 1M length for complex objects are allowed.
308      */
309     @Test
testAllocations_whenWithinLimit()310     public void testAllocations_whenWithinLimit() {
311         Binder.setIsDirectlyHandlingTransactionOverride(true);
312         Parcel p = Parcel.obtain();
313         p.setDataPosition(0);
314         p.writeInt(100000);
315 
316         p.setDataPosition(0);
317         p.createByteArray();
318 
319         p.setDataPosition(0);
320         p.createCharArray();
321 
322         p.setDataPosition(0);
323         p.createIntArray();
324 
325         p.setDataPosition(0);
326         p.createLongArray();
327 
328         p.setDataPosition(0);
329         p.createBinderArray();
330 
331         int[] dimensions = new int[]{ 100, 100, 100 };
332 
333         p.setDataPosition(0);
334         int[][][] data  =  new int[100][100][100];
335         p.writeFixedArray(data, 0, dimensions);
336         p.setDataPosition(0);
337         p.createFixedArray(int[][][].class, dimensions);
338 
339         p.setDataPosition(0);
340         IBinder[][][] parcelables  =  new IBinder[100][100][100];
341         p.writeFixedArray(parcelables, 0, dimensions);
342         p.setDataPosition(0);
343         p.createFixedArray(IBinder[][][].class, dimensions);
344 
345         p.recycle();
346         Binder.setIsDirectlyHandlingTransactionOverride(false);
347     }
348 
349     @Test
testClassCookies()350     public void testClassCookies() {
351         Parcel p = Parcel.obtain();
352         assertThat(p.hasClassCookie(ParcelTest.class)).isFalse();
353 
354         p.setClassCookie(ParcelTest.class, "string_cookie");
355         assertThat(p.hasClassCookie(ParcelTest.class)).isTrue();
356         assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo("string_cookie");
357 
358         p.removeClassCookie(ParcelTest.class, "string_cookie");
359         assertThat(p.hasClassCookie(ParcelTest.class)).isFalse();
360         assertThat(p.getClassCookie(ParcelTest.class)).isEqualTo(null);
361 
362         p.setClassCookie(ParcelTest.class, "to_be_discarded_cookie");
363         p.recycle();
364 
365         // cannot access Parcel after it's recycled!
366         // this test is equivalent to checking hasClassCookie false
367         // after obtaining above
368         // assertThat(p.getClassCookie(ParcelTest.class)).isNull();
369     }
370 
371     @Test
testClassCookies_removeUnexpected()372     public void testClassCookies_removeUnexpected() {
373         Parcel p = Parcel.obtain();
374 
375         assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "not_present"));
376 
377         p.setClassCookie(ParcelTest.class, "value");
378 
379         assertLogsWtf(() -> p.removeClassCookie(ParcelTest.class, "different"));
380         assertThat(p.getClassCookie(ParcelTest.class)).isNull(); // still removed
381 
382         p.recycle();
383     }
384 
assertLogsWtf(Runnable test)385     private static void assertLogsWtf(Runnable test) {
386         ArrayList<Log.TerribleFailure> wtfs = new ArrayList<>();
387         Log.TerribleFailureHandler oldHandler = Log.setWtfHandler(
388                 (tag, what, system) -> wtfs.add(what));
389         try {
390             test.run();
391         } finally {
392             Log.setWtfHandler(oldHandler);
393         }
394         assertThat(wtfs).hasSize(1);
395     }
396 
397     @Test
testHasBinders_AfterWritingBinderToParcel()398     public void testHasBinders_AfterWritingBinderToParcel() {
399         Binder binder = new Binder();
400         Parcel pA = Parcel.obtain();
401         int iA = pA.dataPosition();
402         pA.writeInt(13);
403         assertFalse(pA.hasBinders());
404         pA.writeStrongBinder(binder);
405         assertTrue(pA.hasBinders());
406     }
407 
408     @Test
testHasBindersInRange_AfterWritingBinderToParcel()409     public void testHasBindersInRange_AfterWritingBinderToParcel() {
410         Binder binder = new Binder();
411         Parcel pA = Parcel.obtain();
412         pA.writeInt(13);
413 
414         int binderStartPos = pA.dataPosition();
415         pA.writeStrongBinder(binder);
416         int binderEndPos = pA.dataPosition();
417         assertTrue(pA.hasBinders(binderStartPos, binderEndPos - binderStartPos));
418     }
419 }
420