1 /*
2  * Copyright (C) 2020, 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.aidl.tests;
18 
19 import static org.hamcrest.core.Is.is;
20 import static org.hamcrest.core.IsNull.nullValue;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertThat;
23 import static org.junit.Assume.assumeTrue;
24 import static org.testng.Assert.assertThrows;
25 
26 import android.aidl.tests.extension.ExtendableParcelable;
27 import android.aidl.tests.extension.MyExt;
28 import android.aidl.tests.extension.MyExt2;
29 import android.aidl.tests.extension.MyExtLike;
30 import android.aidl.tests.nonvintf.NonVintfExtendableParcelable;
31 import android.aidl.tests.nonvintf.NonVintfParcelable;
32 import android.aidl.tests.unstable.UnstableExtendableParcelable;
33 import android.aidl.tests.unstable.UnstableParcelable;
34 import android.aidl.tests.vintf.VintfExtendableParcelable;
35 import android.aidl.tests.vintf.VintfParcelable;
36 import android.os.BadParcelableException;
37 import android.os.IBinder;
38 import android.os.Parcel;
39 import android.os.ParcelableHolder;
40 import android.os.RemoteException;
41 import android.os.ServiceManager;
42 import java.util.Arrays;
43 import java.util.HashMap;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.junit.runner.RunWith;
47 import org.junit.runners.JUnit4;
48 
49 @RunWith(JUnit4.class)
50 public class ExtensionTests {
51     private VintfExtendableParcelable vep;
52     private VintfParcelable vp;
53 
54     private NonVintfExtendableParcelable sep;
55     private NonVintfParcelable sp;
56 
57     private UnstableExtendableParcelable uep;
58     private UnstableParcelable up;
59 
60     private ITestService mService;
61     private ICppJavaTests mCppJavaTests;
62 
63     @Before
setUp()64     public void setUp() throws RemoteException {
65       IBinder binder = ServiceManager.waitForService(ITestService.class.getName());
66       assertNotNull(binder);
67       mService = ITestService.Stub.asInterface(binder);
68       assertNotNull(mService);
69 
70       IBinder binder2 = mService.GetCppJavaTests();
71       if (binder2 != null) {
72         mCppJavaTests = ICppJavaTests.Stub.asInterface(binder2);
73       }
74 
75       vep = new VintfExtendableParcelable();
76       vp = new VintfParcelable();
77 
78       sep = new NonVintfExtendableParcelable();
79       sp = new NonVintfParcelable();
80 
81       uep = new UnstableExtendableParcelable();
82       up = new UnstableParcelable();
83     }
84 
85     @Test
testRepeatExtendableParcelable()86     public void testRepeatExtendableParcelable() throws RemoteException {
87       assumeTrue(mCppJavaTests != null);
88 
89       MyExt ext = new MyExt();
90       ext.a = 42;
91       ext.b = "EXT";
92 
93       ExtendableParcelable ep = new ExtendableParcelable();
94       ep.a = 1;
95       ep.b = "a";
96       ep.c = 42L;
97 
98       ep.ext.setParcelable(ext);
99 
100       ExtendableParcelable ep2 = new ExtendableParcelable();
101       mCppJavaTests.RepeatExtendableParcelable(ep, ep2);
102       assertThat(ep2.a, is(ep.a));
103       assertThat(ep2.b, is(ep.b));
104 
105       MyExt retExt = ep2.ext.getParcelable(MyExt.class);
106       assertThat(retExt.a, is(ext.a));
107       assertThat(retExt.b, is(ext.b));
108     }
109 
110     @Test
testVintfParcelableHolderCanContainVintfParcelable()111     public void testVintfParcelableHolderCanContainVintfParcelable() {
112       vep.ext.setParcelable(vp);
113       assertThat(vep.ext.getParcelable(VintfParcelable.class), is(vp));
114     }
115 
116     @Test
testVintfParcelableHolderCannotContainNonVintfParcelable()117     public void testVintfParcelableHolderCannotContainNonVintfParcelable() {
118       assertThrows(BadParcelableException.class, () -> { vep.ext.setParcelable(sp); });
119       assertThat(vep.ext.getParcelable(VintfParcelable.class), is(nullValue()));
120     }
121 
122     @Test
testVintfParcelableHolderCannotContainUnstableParcelable()123     public void testVintfParcelableHolderCannotContainUnstableParcelable() {
124       assertThrows(BadParcelableException.class, () -> { vep.ext.setParcelable(up); });
125       assertThat(vep.ext.getParcelable(UnstableParcelable.class), is(nullValue()));
126     }
127 
128     @Test
testStableParcelableHolderCanContainVintfParcelable()129     public void testStableParcelableHolderCanContainVintfParcelable() {
130       sep.ext.setParcelable(vp);
131       assertThat(sep.ext.getParcelable(VintfParcelable.class), is(vp));
132     }
133 
134     @Test
testStableParcelableHolderCanContainNonVintfParcelable()135     public void testStableParcelableHolderCanContainNonVintfParcelable() {
136       sep.ext.setParcelable(sp);
137       assertThat(sep.ext.getParcelable(NonVintfParcelable.class), is(sp));
138     }
139 
140     @Test
testStableParcelableHolderCanContainUnstableParcelable()141     public void testStableParcelableHolderCanContainUnstableParcelable() {
142       sep.ext.setParcelable(up);
143       assertThat(sep.ext.getParcelable(UnstableParcelable.class), is(up));
144     }
145 
146     @Test
testUnstableParcelableHolderCanContainVintfParcelable()147     public void testUnstableParcelableHolderCanContainVintfParcelable() {
148       uep.ext.setParcelable(vp);
149       assertThat(uep.ext.getParcelable(VintfParcelable.class), is(vp));
150     }
151 
152     @Test
testUnstableParcelableHolderCanContainNonVintfParcelable()153     public void testUnstableParcelableHolderCanContainNonVintfParcelable() {
154       uep.ext.setParcelable(sp);
155       assertThat(uep.ext.getParcelable(NonVintfParcelable.class), is(sp));
156     }
157 
158     @Test
testUnstableParcelableHolderCanContainUnstableParcelable()159     public void testUnstableParcelableHolderCanContainUnstableParcelable() {
160       uep.ext.setParcelable(up);
161       assertThat(uep.ext.getParcelable(UnstableParcelable.class), is(up));
162     }
163 
164     @Test
testReadWriteExtension()165     public void testReadWriteExtension() {
166         MyExt ext = new MyExt();
167         ext.a = 42;
168         ext.b = "EXT";
169 
170         MyExt2 ext2 = new MyExt2();
171         ext2.a = 42;
172         ext2.b = new MyExt();
173         ext2.b.a = 24;
174         ext2.b.b = "INEXT";
175         ext2.c = "EXT2";
176 
177         Parcel parcel = Parcel.obtain();
178         {
179             ExtendableParcelable ep = new ExtendableParcelable();
180             ep.a = 1;
181             ep.b = "a";
182             ep.c = 42L;
183 
184             ep.ext.setParcelable(ext);
185 
186             ep.ext2.setParcelable(ext2);
187             // The extension type must be MyExt, so it has to fail
188             // even though MyExtLike has the same structure as MyExt.
189             assertThrows(BadParcelableException.class,
190                 () -> { MyExtLike extLike = ep.ext.<MyExtLike>getParcelable(MyExtLike.class); });
191 
192             MyExt actualExt = ep.ext.getParcelable(MyExt.class);
193             MyExt2 actualExt2 = ep.ext2.getParcelable(MyExt2.class);
194 
195             checkContent(ep, ext, ext2);
196 
197             ep.writeToParcel(parcel, 0);
198         }
199 
200         parcel.setDataPosition(0);
201         {
202             ExtendableParcelable ep1 = new ExtendableParcelable();
203             ep1.readFromParcel(parcel);
204 
205             parcel.setDataPosition(0);
206             ep1.writeToParcel(parcel, 0);
207             parcel.setDataPosition(0);
208 
209             ExtendableParcelable ep2 = new ExtendableParcelable();
210 
211             ep2.readFromParcel(parcel);
212 
213             // The extension type must be MyExt, so it has to fail
214             // even though MyExtLike has the same structure as MyExt.
215             assertThrows(BadParcelableException.class,
216                 () -> { MyExtLike extLike = ep2.ext.<MyExtLike>getParcelable(MyExtLike.class); });
217 
218             MyExt actualExt = ep2.ext.getParcelable(MyExt.class);
219 
220             MyExt2 newExt2 = new MyExt2();
221             newExt2.a = 79;
222             newExt2.b = new MyExt();
223             newExt2.b.a = 42;
224             newExt2.b.b = "INNEWEXT";
225             newExt2.c = "NEWEXT2";
226             ep2.ext2.setParcelable(newExt2);
227             checkContent(ep1, ext, ext2);
228             checkContent(ep2, ext, newExt2);
229         }
230     }
231 
checkContent(ExtendableParcelable ep, MyExt ext, MyExt2 ext2)232     private void checkContent(ExtendableParcelable ep, MyExt ext, MyExt2 ext2) {
233         assertThat(ep.a, is(1));
234         assertThat(ep.b, is("a"));
235         assertThat(ep.c, is(42L));
236 
237         MyExt actualExt = ep.ext.getParcelable(MyExt.class);
238         assertThat(dumpMyExt(actualExt), is(dumpMyExt(ext)));
239 
240         MyExt2 actualExt2 = ep.ext2.getParcelable(MyExt2.class);
241         assertThat(dumpMyExt2(actualExt2), is(dumpMyExt2(ext2)));
242     }
243 
dumpMyExt(MyExt ext)244     private static String dumpMyExt(MyExt ext) {
245         if (ext == null) {
246             return null;
247         }
248         return "{a: " + ext.a + ", b: " + ext.b + "}";
249     }
250 
dumpMyExt2(MyExt2 ext2)251     private static String dumpMyExt2(MyExt2 ext2) {
252         if (ext2 == null) {
253             return null;
254         }
255         return "{a: " + ext2.a + ", b: " + dumpMyExt(ext2.b) + ", " + ext2.c + "}";
256     }
257 }
258