• 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 package com.android.internal.os;
17 
18 import static com.google.common.truth.Truth.assertThat;
19 
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.reset;
23 import static org.mockito.Mockito.times;
24 import static org.mockito.Mockito.verify;
25 
26 import android.os.DeadObjectException;
27 import android.os.IBinder;
28 import android.os.IBinder.DeathRecipient;
29 import android.os.IInterface;
30 import android.os.Parcel;
31 import android.os.RemoteException;
32 import android.os.ResultReceiver;
33 import android.os.ShellCallback;
34 
35 import androidx.test.filters.SmallTest;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.io.FileDescriptor;
42 
43 @SmallTest
44 @RunWith(AndroidJUnit4.class)
45 public class BinderDeathDispatcherTest {
46     private static class MyTarget implements IInterface, IBinder {
47         public boolean isAlive = true;
48         public DeathRecipient mRecipient;
49 
50         @Override
getInterfaceDescriptor()51         public String getInterfaceDescriptor() throws RemoteException {
52             return null;
53         }
54 
55         @Override
pingBinder()56         public boolean pingBinder() {
57             return false;
58         }
59 
60         @Override
isBinderAlive()61         public boolean isBinderAlive() {
62             return isAlive;
63         }
64 
65         @Override
queryLocalInterface(String descriptor)66         public IInterface queryLocalInterface(String descriptor) {
67             return null;
68         }
69 
70         @Override
dump(FileDescriptor fd, String[] args)71         public void dump(FileDescriptor fd, String[] args) throws RemoteException {
72 
73         }
74 
75         @Override
dumpAsync(FileDescriptor fd, String[] args)76         public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
77 
78         }
79 
80         @Override
shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver)81         public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
82                 String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver)
83                 throws RemoteException {
84 
85         }
86 
87         @Override
transact(int code, Parcel data, Parcel reply, int flags)88         public boolean transact(int code, Parcel data, Parcel reply, int flags)
89                 throws RemoteException {
90             return false;
91         }
92 
93         @Override
linkToDeath(DeathRecipient recipient, int flags)94         public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {
95             // In any situation, a single binder object should only have at most one death
96             // recipient.
97             assertThat(mRecipient).isNull();
98 
99             if (!isAlive) {
100                 throw new DeadObjectException();
101             }
102 
103             mRecipient = recipient;
104         }
105 
106         @Override
unlinkToDeath(DeathRecipient recipient, int flags)107         public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
108             if (!isAlive) {
109                 return false;
110             }
111             assertThat(mRecipient).isSameInstanceAs(recipient);
112             mRecipient = null;
113             return true;
114         }
115 
116         @Override
asBinder()117         public IBinder asBinder() {
118             return this;
119         }
120 
die()121         public void die() {
122             isAlive = false;
123             if (mRecipient != null) {
124                 mRecipient.binderDied(this);
125             }
126             mRecipient = null;
127         }
128 
hasDeathRecipient()129         public boolean hasDeathRecipient() {
130             return mRecipient != null;
131         }
132     }
133 
134     @Test
testRegisterAndUnregister()135     public void testRegisterAndUnregister() {
136         BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
137 
138         MyTarget t1 = new MyTarget();
139         MyTarget t2 = new MyTarget();
140         MyTarget t3 = new MyTarget();
141 
142         DeathRecipient r1 = mock(DeathRecipient.class);
143         DeathRecipient r2 = mock(DeathRecipient.class);
144         DeathRecipient r3 = mock(DeathRecipient.class);
145         DeathRecipient r4 = mock(DeathRecipient.class);
146         DeathRecipient r5 = mock(DeathRecipient.class);
147 
148         // Start hooking up.
149 
150         // Link 3 recipients to t1 -- only one real recipient will be set.
151         assertThat(d.linkToDeath(t1, r1)).isEqualTo(1);
152         assertThat(d.getTargetsForTest().size()).isEqualTo(1);
153 
154         assertThat(d.linkToDeath(t1, r2)).isEqualTo(2);
155         assertThat(d.linkToDeath(t1, r3)).isEqualTo(3);
156         assertThat(d.getTargetsForTest().size()).isEqualTo(1);
157 
158         // Unlink two -- the real recipient is still set.
159         d.unlinkToDeath(t1, r1);
160         d.unlinkToDeath(t1, r2);
161 
162         assertThat(t1.hasDeathRecipient()).isTrue();
163         assertThat(d.getTargetsForTest().size()).isEqualTo(1);
164 
165         // Unlink the last one. The real recipient is also unlinked.
166         d.unlinkToDeath(t1, r3);
167         assertThat(t1.hasDeathRecipient()).isFalse();
168         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
169 
170         // Set recipients to t1, t2 and t3. t3 has two.
171         assertThat(d.linkToDeath(t1, r1)).isEqualTo(1);
172         assertThat(d.linkToDeath(t2, r1)).isEqualTo(1);
173         assertThat(d.linkToDeath(t3, r1)).isEqualTo(1);
174         assertThat(d.linkToDeath(t3, r2)).isEqualTo(2);
175 
176 
177         // They should all have a real recipient.
178         assertThat(t1.hasDeathRecipient()).isTrue();
179         assertThat(t2.hasDeathRecipient()).isTrue();
180         assertThat(t3.hasDeathRecipient()).isTrue();
181 
182         assertThat(d.getTargetsForTest().size()).isEqualTo(3);
183 
184         // Unlink r1 from t3. t3 still has r2, so it should still have a real recipient.
185         d.unlinkToDeath(t3, r1);
186         assertThat(t1.hasDeathRecipient()).isTrue();
187         assertThat(t2.hasDeathRecipient()).isTrue();
188         assertThat(t3.hasDeathRecipient()).isTrue();
189         assertThat(d.getTargetsForTest().size()).isEqualTo(3);
190 
191         // Unlink r2 from t3. Now t3 has no real recipient.
192         d.unlinkToDeath(t3, r2);
193         assertThat(t3.hasDeathRecipient()).isFalse();
194         assertThat(d.getTargetsForTest().size()).isEqualTo(2);
195     }
196 
197     @Test
testRegisterAndKill()198     public void testRegisterAndKill() {
199         BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
200 
201         MyTarget t1 = new MyTarget();
202         MyTarget t2 = new MyTarget();
203         MyTarget t3 = new MyTarget();
204 
205         DeathRecipient r1 = mock(DeathRecipient.class);
206         DeathRecipient r2 = mock(DeathRecipient.class);
207         DeathRecipient r3 = mock(DeathRecipient.class);
208         DeathRecipient r4 = mock(DeathRecipient.class);
209         DeathRecipient r5 = mock(DeathRecipient.class);
210 
211         // Hook them up.
212 
213         d.linkToDeath(t1, r1);
214         d.linkToDeath(t1, r2);
215         d.linkToDeath(t1, r3);
216 
217         // r4 is linked then unlinked. It shouldn't be notified.
218         d.linkToDeath(t1, r4);
219         d.unlinkToDeath(t1, r4);
220 
221         d.linkToDeath(t2, r1);
222 
223         d.linkToDeath(t3, r3);
224         d.linkToDeath(t3, r5);
225 
226         assertThat(d.getTargetsForTest().size()).isEqualTo(3);
227 
228         // Kill the targets.
229 
230         t1.die();
231         verify(r1, times(1)).binderDied(t1);
232         verify(r2, times(1)).binderDied(t1);
233         verify(r3, times(1)).binderDied(t1);
234         verify(r4, times(0)).binderDied(any());
235         verify(r5, times(0)).binderDied(any());
236 
237         assertThat(d.getTargetsForTest().size()).isEqualTo(2);
238 
239         reset(r1, r2, r3, r4, r5);
240 
241         t2.die();
242         verify(r1, times(1)).binderDied(t2);
243         verify(r2, times(0)).binderDied(any());
244         verify(r3, times(0)).binderDied(any());
245         verify(r4, times(0)).binderDied(any());
246         verify(r5, times(0)).binderDied(any());
247 
248         assertThat(d.getTargetsForTest().size()).isEqualTo(1);
249 
250         reset(r1, r2, r3, r4, r5);
251 
252         t3.die();
253         verify(r1, times(0)).binderDied(any());
254         verify(r2, times(0)).binderDied(any());
255         verify(r3, times(1)).binderDied(t3);
256         verify(r4, times(0)).binderDied(any());
257         verify(r5, times(1)).binderDied(t3);
258 
259         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
260 
261         // Try to register to a dead object -> should return -1.
262         assertThat(d.linkToDeath(t1, r1)).isEqualTo(-1);
263 
264         assertThat(d.getTargetsForTest().size()).isEqualTo(0);
265     }
266 
267     @Test
duplicateRegistrations()268     public void duplicateRegistrations() {
269         BinderDeathDispatcher<MyTarget> d = new BinderDeathDispatcher<>();
270 
271         MyTarget t1 = new MyTarget();
272 
273         DeathRecipient r1 = mock(DeathRecipient.class);
274         DeathRecipient r2 = mock(DeathRecipient.class);
275 
276         for (int i = 0; i < 5; i++) {
277             assertThat(d.linkToDeath(t1, r1)).isEqualTo(1);
278         }
279         assertThat(d.linkToDeath(t1, r2)).isEqualTo(2);
280 
281         t1.die();
282         verify(r1, times(1)).binderDied(t1);
283         verify(r2, times(1)).binderDied(t1);
284 
285         d.unlinkToDeath(t1, r1);
286         d.unlinkToDeath(t1, r2);
287         assertThat(d.getTargetsForTest()).isEmpty();
288     }
289 }
290