blob: c159007593c5e6124b71cc1b6e7acae2bd73a67e [file] [log] [blame]
keunyoung6b197692015-11-16 13:54:38 -08001/*
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
17package com.android.car;
18
19import android.annotation.Nullable;
20import android.os.IBinder;
21import android.os.IInterface;
22import android.os.RemoteException;
23
Antonio Kantekd9ae7802019-11-13 20:09:06 -080024import com.android.internal.annotations.GuardedBy;
25
Hayden Gomes04ecb142020-12-02 13:52:03 -080026import java.util.ArrayList;
keunyoung6b197692015-11-16 13:54:38 -080027import java.util.Collection;
28import java.util.HashMap;
Antonio Kantekd9ae7802019-11-13 20:09:06 -080029import java.util.Map;
keunyoung6b197692015-11-16 13:54:38 -080030
31/**
32 * Helper class to hold client's binder interface.
Antonio Kantekd9ae7802019-11-13 20:09:06 -080033 *
34 * @param <T> type of the value that is wrapped by this class
keunyoung6b197692015-11-16 13:54:38 -080035 */
36public class BinderInterfaceContainer<T extends IInterface> {
37
Antonio Kantekd9ae7802019-11-13 20:09:06 -080038 /**
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 {
keunyounge4c90c42015-11-16 18:42:52 -080045 public final T binderInterface;
keunyoung6b197692015-11-16 13:54:38 -080046 private final BinderInterfaceContainer<T> mContainer;
47
Keun-young Parke54ac272016-02-16 19:02:18 -080048 public BinderInterface(BinderInterfaceContainer<T> container, T binderInterface) {
keunyoung6b197692015-11-16 13:54:38 -080049 mContainer = container;
keunyounge4c90c42015-11-16 18:42:52 -080050 this.binderInterface = binderInterface;
keunyoung6b197692015-11-16 13:54:38 -080051 }
52
53 @Override
54 public void binderDied() {
55 binderInterface.asBinder().unlinkToDeath(this, 0);
keunyounge4c90c42015-11-16 18:42:52 -080056 mContainer.handleBinderDeath(this);
keunyoung6b197692015-11-16 13:54:38 -080057 }
58 }
59
Antonio Kantekd9ae7802019-11-13 20:09:06 -080060 /**
61 * Interface to be implemented by object that want to be notified whenever a binder is unliked
62 * (dies).
63 */
keunyoung6b197692015-11-16 13:54:38 -080064 public interface BinderEventHandler<T extends IInterface> {
65 void onBinderDeath(BinderInterface<T> bInterface);
66 }
67
Antonio Kantekd9ae7802019-11-13 20:09:06 -080068 private final Object mLock = new Object();
keunyoung6b197692015-11-16 13:54:38 -080069
Antonio Kantekd9ae7802019-11-13 20:09:06 -080070 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 */
keunyoung6b197692015-11-16 13:54:38 -080079 public BinderInterfaceContainer(@Nullable BinderEventHandler<T> eventHandler) {
80 mEventHandler = eventHandler;
81 }
82
Keun-young Parkfe1a8f12017-01-17 20:06:34 -080083 public BinderInterfaceContainer() {
84 mEventHandler = null;
85 }
86
Antonio Kantekd9ae7802019-11-13 20:09:06 -080087 /**
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 */
Keun-young Parke54ac272016-02-16 19:02:18 -080092 public void addBinder(T binderInterface) {
keunyoung6b197692015-11-16 13:54:38 -080093 IBinder binder = binderInterface.asBinder();
Antonio Kantekd9ae7802019-11-13 20:09:06 -080094 synchronized (mLock) {
keunyounge4c90c42015-11-16 18:42:52 -080095 BinderInterface<T> bInterface = mBinders.get(binder);
keunyoung6b197692015-11-16 13:54:38 -080096 if (bInterface != null) {
97 return;
98 }
Keun-young Parke54ac272016-02-16 19:02:18 -080099 bInterface = new BinderInterface<T>(this, binderInterface);
keunyoung6b197692015-11-16 13:54:38 -0800100 try {
101 binder.linkToDeath(bInterface, 0);
102 } catch (RemoteException e) {
103 throw new IllegalArgumentException(e);
104 }
105 mBinders.put(binder, bInterface);
106 }
107 }
108
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800109 /**
110 * Removes the {@link BinderInterface} object associated with the passed parameter (if there is
111 * any).
112 */
keunyoung6b197692015-11-16 13:54:38 -0800113 public void removeBinder(T binderInterface) {
114 IBinder binder = binderInterface.asBinder();
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800115 synchronized (mLock) {
keunyounge4c90c42015-11-16 18:42:52 -0800116 BinderInterface<T> bInterface = mBinders.get(binder);
Keun-young Parkc26f6be2016-10-11 19:59:08 -0700117 if (bInterface == null) {
keunyoung6b197692015-11-16 13:54:38 -0800118 return;
119 }
120 binder.unlinkToDeath(bInterface, 0);
121 mBinders.remove(binder);
122 }
123 }
124
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800125 /**
126 * Returns the {@link BinderInterface} object associated with the passed parameter.
127 */
keunyounge4c90c42015-11-16 18:42:52 -0800128 public BinderInterface<T> getBinderInterface(T binderInterface) {
129 IBinder binder = binderInterface.asBinder();
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800130 synchronized (mLock) {
keunyounge4c90c42015-11-16 18:42:52 -0800131 return mBinders.get(binder);
132 }
133 }
134
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800135 /**
136 * Adds a new {@link BinderInterface} in this container.
137 */
keunyounge4c90c42015-11-16 18:42:52 -0800138 public void addBinderInterface(BinderInterface<T> bInterface) {
139 IBinder binder = bInterface.binderInterface.asBinder();
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800140 synchronized (mLock) {
keunyounge4c90c42015-11-16 18:42:52 -0800141 try {
142 binder.linkToDeath(bInterface, 0);
143 } catch (RemoteException e) {
144 throw new IllegalArgumentException(e);
145 }
146 mBinders.put(binder, bInterface);
147 }
148 }
149
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800150 /**
Hayden Gomes04ecb142020-12-02 13:52:03 -0800151 * Returns a shallow copy of all registered {@link BinderInterface} objects in this container.
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800152 */
keunyoung6b197692015-11-16 13:54:38 -0800153 public Collection<BinderInterface<T>> getInterfaces() {
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800154 synchronized (mLock) {
Hayden Gomes04ecb142020-12-02 13:52:03 -0800155 return new ArrayList<>(mBinders.values());
keunyoung6b197692015-11-16 13:54:38 -0800156 }
157 }
158
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800159 /**
160 * Returns the number of registered {@link BinderInterface} objects in this container.
161 */
162 public int size() {
163 synchronized (mLock) {
164 return mBinders.size();
165 }
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800166 }
167
Antonio Kantekd9ae7802019-11-13 20:09:06 -0800168 /**
169 * Clears all registered {@link BinderInterface} objects.
170 */
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 }
keunyoung6b197692015-11-16 13:54:38 -0800178 }
Keun young Parkbbd35f72019-11-26 08:08:24 -0800179 mBinders.clear();
keunyoung6b197692015-11-16 13:54:38 -0800180 }
181
182 private void handleBinderDeath(BinderInterface<T> bInterface) {
keunyoung6b197692015-11-16 13:54:38 -0800183 if (mEventHandler != null) {
184 mEventHandler.onBinderDeath(bInterface);
185 }
Keun young Parka7bdd592020-04-15 17:57:40 -0700186 removeBinder(bInterface.binderInterface);
keunyoung6b197692015-11-16 13:54:38 -0800187 }
188}