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 com.android.internal.annotations.GuardedBy; 25 26 import java.util.ArrayList; 27 import java.util.Collection; 28 import java.util.HashMap; 29 import java.util.Map; 30 31 /** 32 * Helper class to hold client's binder interface. 33 * 34 * @param <T> type of the value that is wrapped by this class 35 */ 36 public class BinderInterfaceContainer<T extends IInterface> { 37 38 /** 39 * Wrapper class for objects that want to be notified whenever they are unliked from 40 * the container ({@link BinderInterfaceContainer}). 41 * 42 * @param <T> type of the value that is wrapped by this class 43 */ 44 public static class BinderInterface<T extends IInterface> implements IBinder.DeathRecipient { 45 public final T binderInterface; 46 private final BinderInterfaceContainer<T> mContainer; 47 BinderInterface(BinderInterfaceContainer<T> container, T binderInterface)48 public BinderInterface(BinderInterfaceContainer<T> container, T binderInterface) { 49 mContainer = container; 50 this.binderInterface = binderInterface; 51 } 52 53 @Override binderDied()54 public void binderDied() { 55 binderInterface.asBinder().unlinkToDeath(this, 0); 56 mContainer.handleBinderDeath(this); 57 } 58 } 59 60 /** 61 * Interface to be implemented by object that want to be notified whenever a binder is unliked 62 * (dies). 63 */ 64 public interface BinderEventHandler<T extends IInterface> { onBinderDeath(BinderInterface<T> bInterface)65 void onBinderDeath(BinderInterface<T> bInterface); 66 } 67 68 private final Object mLock = new Object(); 69 70 private final BinderEventHandler<T> mEventHandler; 71 72 @GuardedBy("mLock") 73 private final Map<IBinder, BinderInterface<T>> mBinders = new HashMap<>(); 74 75 /** 76 * Constructs a new <code>BinderInterfaceContainer</code> passing an event handler to be used to 77 * notify listeners when a registered binder dies (unlinked). 78 */ BinderInterfaceContainer(@ullable BinderEventHandler<T> eventHandler)79 public BinderInterfaceContainer(@Nullable BinderEventHandler<T> eventHandler) { 80 mEventHandler = eventHandler; 81 } 82 BinderInterfaceContainer()83 public BinderInterfaceContainer() { 84 mEventHandler = null; 85 } 86 87 /** 88 * Add the instance of {@link IInterface} representing the binder interface to this container. 89 * 90 * Internally, this object will be wrapped in an {@link BinderInterface} when added. 91 */ addBinder(T binderInterface)92 public void addBinder(T binderInterface) { 93 IBinder binder = binderInterface.asBinder(); 94 synchronized (mLock) { 95 BinderInterface<T> bInterface = mBinders.get(binder); 96 if (bInterface != null) { 97 return; 98 } 99 bInterface = new BinderInterface<T>(this, binderInterface); 100 try { 101 binder.linkToDeath(bInterface, 0); 102 } catch (RemoteException e) { 103 throw new IllegalArgumentException(e); 104 } 105 mBinders.put(binder, bInterface); 106 } 107 } 108 109 /** 110 * Removes the {@link BinderInterface} object associated with the passed parameter (if there is 111 * any). 112 */ removeBinder(T binderInterface)113 public void removeBinder(T binderInterface) { 114 IBinder binder = binderInterface.asBinder(); 115 synchronized (mLock) { 116 BinderInterface<T> bInterface = mBinders.get(binder); 117 if (bInterface == null) { 118 return; 119 } 120 binder.unlinkToDeath(bInterface, 0); 121 mBinders.remove(binder); 122 } 123 } 124 125 /** 126 * Returns the {@link BinderInterface} object associated with the passed parameter. 127 */ getBinderInterface(T binderInterface)128 public BinderInterface<T> getBinderInterface(T binderInterface) { 129 IBinder binder = binderInterface.asBinder(); 130 synchronized (mLock) { 131 return mBinders.get(binder); 132 } 133 } 134 135 /** 136 * Adds a new {@link BinderInterface} in this container. 137 */ addBinderInterface(BinderInterface<T> bInterface)138 public void addBinderInterface(BinderInterface<T> bInterface) { 139 IBinder binder = bInterface.binderInterface.asBinder(); 140 synchronized (mLock) { 141 try { 142 binder.linkToDeath(bInterface, 0); 143 } catch (RemoteException e) { 144 throw new IllegalArgumentException(e); 145 } 146 mBinders.put(binder, bInterface); 147 } 148 } 149 150 /** 151 * Returns a shallow copy of all registered {@link BinderInterface} objects in this container. 152 */ getInterfaces()153 public Collection<BinderInterface<T>> getInterfaces() { 154 synchronized (mLock) { 155 return new ArrayList<>(mBinders.values()); 156 } 157 } 158 159 /** 160 * Returns the number of registered {@link BinderInterface} objects in this container. 161 */ size()162 public int size() { 163 synchronized (mLock) { 164 return mBinders.size(); 165 } 166 } 167 168 /** 169 * Clears all registered {@link BinderInterface} objects. 170 */ clear()171 public void clear() { 172 synchronized (mLock) { 173 Collection<BinderInterface<T>> interfaces = getInterfaces(); 174 for (BinderInterface<T> bInterface : interfaces) { 175 IBinder binder = bInterface.binderInterface.asBinder(); 176 binder.unlinkToDeath(bInterface, 0); 177 } 178 mBinders.clear(); 179 } 180 } 181 handleBinderDeath(BinderInterface<T> bInterface)182 private void handleBinderDeath(BinderInterface<T> bInterface) { 183 if (mEventHandler != null) { 184 mEventHandler.onBinderDeath(bInterface); 185 } 186 removeBinder(bInterface.binderInterface); 187 } 188 } 189