1 /* 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 17 package com.android.server.location; 18 19 import com.android.internal.util.Preconditions; 20 21 import android.annotation.NonNull; 22 import android.os.IBinder; 23 import android.os.IInterface; 24 import android.os.RemoteException; 25 import android.util.Log; 26 27 import java.util.ArrayList; 28 import java.util.Collection; 29 import java.util.HashMap; 30 31 /** 32 * A helper class, that handles operations in remote listeners, and tracks for remote process death. 33 */ 34 abstract class RemoteListenerHelper<TListener extends IInterface> { 35 private final String mTag; 36 private final HashMap<IBinder, LinkedListener> mListenerMap = 37 new HashMap<IBinder, LinkedListener>(); 38 39 protected RemoteListenerHelper(String name) { 40 Preconditions.checkNotNull(name); 41 mTag = name; 42 } 43 44 public boolean addListener(@NonNull TListener listener) { 45 Preconditions.checkNotNull(listener, "Attempted to register a 'null' listener."); 46 if (!isSupported()) { 47 Log.e(mTag, "Refused to add listener, the feature is not supported."); 48 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 64 Log.e(mTag, "Remote listener already died.", e); 65 return false; 66 } 67 68 mListenerMap.put(binder, deathListener); 69 if (mListenerMap.size() == 1) { 70 if (!registerWithService()) { 71 Log.e(mTag, "RegisterWithService failed, listener will be removed."); 72 removeListener(listener); 73 return false; 74 } 75 } 76 } 77 78 return true; 79 } 80 81 public boolean removeListener(@NonNull TListener listener) { 82 Preconditions.checkNotNull(listener, "Attempted to remove a 'null' listener."); 83 if (!isSupported()) { 84 Log.e(mTag, "Refused to remove listener, the feature is not supported."); 85 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) { 93 unregisterFromService(); 94 } 95 } 96 97 if (linkedListener != null) { 98 binder.unlinkToDeath(linkedListener, 0 /* flags */); 99 } 100 return true; 101 } 102 103 protected abstract boolean isSupported(); 104 protected abstract boolean registerWithService(); 105 protected abstract void unregisterFromService(); 106 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) { 123 Log.e(mTag, "Error in monitored listener.", e); 124 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() { 143 Log.d(mTag, "Remote Listener died: " + mListener); 144 removeListener(mListener); 145 } 146 } 147 } 148