blob: 451af18d12437d5b49a96a70ec39d34a461b9008 [file] [log] [blame]
destradaaea8a8a62014-06-23 18:19:03 -07001/*
2 * Copyright (C) 2014 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.server.location;
18
19import com.android.internal.util.Preconditions;
20
21import android.annotation.NonNull;
22import android.os.IBinder;
23import android.os.IInterface;
24import android.os.RemoteException;
25import android.util.Log;
26
27import java.util.ArrayList;
28import java.util.Collection;
29import java.util.HashMap;
30
31/**
32 * A helper class, that handles operations in remote listeners, and tracks for remote process death.
33 */
34abstract class RemoteListenerHelper<TListener extends IInterface> {
destradaa4b3e3932014-07-21 18:01:47 -070035 private final String mTag;
destradaaea8a8a62014-06-23 18:19:03 -070036 private final HashMap<IBinder, LinkedListener> mListenerMap =
37 new HashMap<IBinder, LinkedListener>();
38
destradaa4b3e3932014-07-21 18:01:47 -070039 protected RemoteListenerHelper(String name) {
40 Preconditions.checkNotNull(name);
41 mTag = name;
42 }
43
destradaaea8a8a62014-06-23 18:19:03 -070044 public boolean addListener(@NonNull TListener listener) {
45 Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener.");
destradaaea8a8a62014-06-23 18:19:03 -070046 if (!isSupported()) {
destradaa4b3e3932014-07-21 18:01:47 -070047 Log.e(mTag, "Refused to add listener, the feature is not supported.");
destradaaea8a8a62014-06-23 18:19:03 -070048 return false;
49 }
50
51 IBinder binder = listener.asBinder();
52 LinkedListener deathListener = new LinkedListener(listener);
53 synchronized (mListenerMap) {
54 if (mListenerMap.containsKey(binder)) {
55 // listener already added
56 return true;
57 }
58
59 try {
60 binder.linkToDeath(deathListener, 0 /* flags */);
61 } catch (RemoteException e) {
62 // if the remote process registering the listener is already death, just swallow the
63 // exception and continue
destradaa4b3e3932014-07-21 18:01:47 -070064 Log.e(mTag, "Remote listener already died.", e);
destradaaea8a8a62014-06-23 18:19:03 -070065 return false;
66 }
67
68 mListenerMap.put(binder, deathListener);
69 if (mListenerMap.size() == 1) {
destradaa4b3e3932014-07-21 18:01:47 -070070 if (!registerWithService()) {
71 Log.e(mTag, "RegisterWithService failed, listener will be removed.");
72 removeListener(listener);
73 return false;
74 }
destradaaea8a8a62014-06-23 18:19:03 -070075 }
76 }
77
78 return true;
79 }
80
81 public boolean removeListener(@NonNull TListener listener) {
82 Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener.");
destradaaea8a8a62014-06-23 18:19:03 -070083 if (!isSupported()) {
destradaa4b3e3932014-07-21 18:01:47 -070084 Log.e(mTag, "Refused to remove listener, the feature is not supported.");
destradaaea8a8a62014-06-23 18:19:03 -070085 return false;
86 }
87
88 IBinder binder = listener.asBinder();
89 LinkedListener linkedListener;
90 synchronized (mListenerMap) {
91 linkedListener = mListenerMap.remove(binder);
92 if (mListenerMap.isEmpty() && linkedListener != null) {
destradaa4b3e3932014-07-21 18:01:47 -070093 unregisterFromService();
destradaaea8a8a62014-06-23 18:19:03 -070094 }
95 }
96
97 if (linkedListener != null) {
98 binder.unlinkToDeath(linkedListener, 0 /* flags */);
99 }
destradaaea8a8a62014-06-23 18:19:03 -0700100 return true;
101 }
102
103 protected abstract boolean isSupported();
destradaa4b3e3932014-07-21 18:01:47 -0700104 protected abstract boolean registerWithService();
105 protected abstract void unregisterFromService();
destradaaea8a8a62014-06-23 18:19:03 -0700106
107 protected interface ListenerOperation<TListener extends IInterface> {
108 void execute(TListener listener) throws RemoteException;
109 }
110
111 protected void foreach(ListenerOperation operation) {
112 Collection<LinkedListener> linkedListeners;
113 synchronized (mListenerMap) {
114 Collection<LinkedListener> values = mListenerMap.values();
115 linkedListeners = new ArrayList<LinkedListener>(values);
116 }
117
118 for (LinkedListener linkedListener : linkedListeners) {
119 TListener listener = linkedListener.getUnderlyingListener();
120 try {
121 operation.execute(listener);
122 } catch (RemoteException e) {
destradaa4b3e3932014-07-21 18:01:47 -0700123 Log.e(mTag, "Error in monitored listener.", e);
destradaaea8a8a62014-06-23 18:19:03 -0700124 removeListener(listener);
125 }
126 }
127 }
128
129 private class LinkedListener implements IBinder.DeathRecipient {
130 private final TListener mListener;
131
132 public LinkedListener(@NonNull TListener listener) {
133 mListener = listener;
134 }
135
136 @NonNull
137 public TListener getUnderlyingListener() {
138 return mListener;
139 }
140
141 @Override
142 public void binderDied() {
destradaa4b3e3932014-07-21 18:01:47 -0700143 Log.d(mTag, "Remote Listener died: " + mListener);
destradaaea8a8a62014-06-23 18:19:03 -0700144 removeListener(mListener);
145 }
146 }
147}