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 
BinderInterfaceContainer()60     public BinderInterfaceContainer() {
61         mEventHandler = null;
62     }
63 
addBinder(T binderInterface)64     public void addBinder(T binderInterface) {
65         IBinder binder = binderInterface.asBinder();
66         synchronized (this) {
67             BinderInterface<T> bInterface = mBinders.get(binder);
68             if (bInterface != null) {
69                 return;
70             }
71             bInterface = new BinderInterface<T>(this, binderInterface);
72             try {
73                 binder.linkToDeath(bInterface, 0);
74             } catch (RemoteException e) {
75                 throw new IllegalArgumentException(e);
76             }
77             mBinders.put(binder, bInterface);
78         }
79     }
80 
removeBinder(T binderInterface)81     public void removeBinder(T binderInterface) {
82         IBinder binder = binderInterface.asBinder();
83         synchronized(this) {
84             BinderInterface<T> bInterface = mBinders.get(binder);
85             if (bInterface == null) {
86                 return;
87             }
88             binder.unlinkToDeath(bInterface, 0);
89             mBinders.remove(binder);
90         }
91     }
92 
getBinderInterface(T binderInterface)93     public BinderInterface<T> getBinderInterface(T binderInterface) {
94         IBinder binder = binderInterface.asBinder();
95         synchronized (this) {
96             return mBinders.get(binder);
97         }
98     }
99 
addBinderInterface(BinderInterface<T> bInterface)100     public void addBinderInterface(BinderInterface<T> bInterface) {
101         IBinder binder = bInterface.binderInterface.asBinder();
102         synchronized (this) {
103             try {
104                 binder.linkToDeath(bInterface, 0);
105             } catch (RemoteException e) {
106                 throw new IllegalArgumentException(e);
107             }
108             mBinders.put(binder, bInterface);
109         }
110     }
111 
getInterfaces()112     public Collection<BinderInterface<T>> getInterfaces() {
113         synchronized (this) {
114             return mBinders.values();
115         }
116     }
117 
size()118     public synchronized int size() {
119         return mBinders.size();
120     }
121 
clear()122     public synchronized void clear() {
123         Collection<BinderInterface<T>> interfaces = getInterfaces();
124         for (BinderInterface<T> bInterface : interfaces) {
125             IBinder binder = bInterface.binderInterface.asBinder();
126             binder.unlinkToDeath(bInterface, 0);
127         }
128         mBinders.clear();
129     }
130 
handleBinderDeath(BinderInterface<T> bInterface)131     private void handleBinderDeath(BinderInterface<T> bInterface) {
132         removeBinder(bInterface.binderInterface);
133         if (mEventHandler != null) {
134             mEventHandler.onBinderDeath(bInterface);
135         }
136     }
137 }
138