1 /*
2  * Copyright (C) 2015 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 com.android.car;
18 
19 import android.annotation.Nullable;
20 import android.os.IBinder;
21 import android.os.IInterface;
22 import android.os.RemoteException;
23 
24 import java.util.Collection;
25 import java.util.HashMap;
26 
27 /**
28  * Helper class to hold client's binder interface.
29  */
30 public class BinderInterfaceContainer<T extends IInterface> {
31 
32     public static class BinderInterface<T extends IInterface>
33             implements IBinder.DeathRecipient {
34         public final T binderInterface;
35         private final BinderInterfaceContainer<T> mContainer;
36 
BinderInterface(BinderInterfaceContainer<T> container, T binderInterface)37         public BinderInterface(BinderInterfaceContainer<T> container, T binderInterface) {
38             mContainer = container;
39             this.binderInterface = binderInterface;
40         }
41 
42         @Override
binderDied()43         public void binderDied() {
44             binderInterface.asBinder().unlinkToDeath(this, 0);
45             mContainer.handleBinderDeath(this);
46         }
47     }
48 
49     public interface BinderEventHandler<T extends IInterface> {
onBinderDeath(BinderInterface<T> bInterface)50         void onBinderDeath(BinderInterface<T> bInterface);
51     }
52 
53     private final BinderEventHandler<T> mEventHandler;
54     private final HashMap<IBinder, BinderInterface<T>> mBinders = new HashMap<>();
55 
BinderInterfaceContainer(@ullable BinderEventHandler<T> eventHandler)56     public BinderInterfaceContainer(@Nullable BinderEventHandler<T> eventHandler) {
57         mEventHandler = eventHandler;
58     }
59 
addBinder(T binderInterface)60     public void addBinder(T binderInterface) {
61         IBinder binder = binderInterface.asBinder();
62         synchronized (this) {
63             BinderInterface<T> bInterface = mBinders.get(binder);
64             if (bInterface != null) {
65                 return;
66             }
67             bInterface = new BinderInterface<T>(this, binderInterface);
68             try {
69                 binder.linkToDeath(bInterface, 0);
70             } catch (RemoteException e) {
71                 throw new IllegalArgumentException(e);
72             }
73             mBinders.put(binder, bInterface);
74         }
75     }
76 
removeBinder(T binderInterface)77     public void removeBinder(T binderInterface) {
78         IBinder binder = binderInterface.asBinder();
79         synchronized(this) {
80             BinderInterface<T> bInterface = mBinders.get(binder);
81             if (bInterface != null) {
82                 return;
83             }
84             binder.unlinkToDeath(bInterface, 0);
85             mBinders.remove(binder);
86         }
87     }
88 
getBinderInterface(T binderInterface)89     public BinderInterface<T> getBinderInterface(T binderInterface) {
90         IBinder binder = binderInterface.asBinder();
91         synchronized (this) {
92             return mBinders.get(binder);
93         }
94     }
95 
addBinderInterface(BinderInterface<T> bInterface)96     public void addBinderInterface(BinderInterface<T> bInterface) {
97         IBinder binder = bInterface.binderInterface.asBinder();
98         synchronized (this) {
99             try {
100                 binder.linkToDeath(bInterface, 0);
101             } catch (RemoteException e) {
102                 throw new IllegalArgumentException(e);
103             }
104             mBinders.put(binder, bInterface);
105         }
106     }
107 
getInterfaces()108     public Collection<BinderInterface<T>> getInterfaces() {
109         synchronized (this) {
110             return mBinders.values();
111         }
112     }
113 
clear()114     public synchronized void clear() {
115         Collection<BinderInterface<T>> interfaces = getInterfaces();
116         for (BinderInterface<T> bInterface : interfaces) {
117             removeBinder(bInterface.binderInterface);
118         }
119     }
120 
handleBinderDeath(BinderInterface<T> bInterface)121     private void handleBinderDeath(BinderInterface<T> bInterface) {
122         removeBinder(bInterface.binderInterface);
123         if (mEventHandler != null) {
124             mEventHandler.onBinderDeath(bInterface);
125         }
126     }
127 }
128