• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2018 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.broadcastradio.hal2;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.hardware.radio.Announcement;
22 import android.hardware.radio.IAnnouncementListener;
23 import android.hardware.radio.ICloseHandle;
24 import android.os.IBinder;
25 import android.os.RemoteException;
26 import android.util.Slog;
27 
28 import com.android.internal.annotations.GuardedBy;
29 
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.List;
33 import java.util.Objects;
34 
35 public class AnnouncementAggregator extends ICloseHandle.Stub {
36     private static final String TAG = "BcRadio2Srv.AnnAggr";
37 
38     private final Object mLock;
39     @NonNull private final IAnnouncementListener mListener;
40     private final IBinder.DeathRecipient mDeathRecipient = new DeathRecipient();
41 
42     @GuardedBy("mLock")
43     private final Collection<ModuleWatcher> mModuleWatchers = new ArrayList<>();
44 
45     @GuardedBy("mLock")
46     private boolean mIsClosed = false;
47 
AnnouncementAggregator(@onNull IAnnouncementListener listener, @NonNull Object lock)48     public AnnouncementAggregator(@NonNull IAnnouncementListener listener, @NonNull Object lock) {
49         mListener = Objects.requireNonNull(listener);
50         mLock = Objects.requireNonNull(lock);
51         try {
52             listener.asBinder().linkToDeath(mDeathRecipient, 0);
53         } catch (RemoteException ex) {
54             ex.rethrowFromSystemServer();
55         }
56     }
57 
58     private class ModuleWatcher extends IAnnouncementListener.Stub {
59         private @Nullable ICloseHandle mCloseHandle;
60         public @NonNull List<Announcement> currentList = new ArrayList<>();
61 
onListUpdated(List<Announcement> active)62         public void onListUpdated(List<Announcement> active) {
63             currentList = Objects.requireNonNull(active);
64             AnnouncementAggregator.this.onListUpdated();
65         }
66 
setCloseHandle(@onNull ICloseHandle closeHandle)67         public void setCloseHandle(@NonNull ICloseHandle closeHandle) {
68             mCloseHandle = Objects.requireNonNull(closeHandle);
69         }
70 
close()71         public void close() throws RemoteException {
72             if (mCloseHandle != null) mCloseHandle.close();
73         }
74     }
75 
76     private class DeathRecipient implements IBinder.DeathRecipient {
binderDied()77         public void binderDied() {
78             try {
79                 close();
80             } catch (RemoteException ex) {}
81         }
82     }
83 
onListUpdated()84     private void onListUpdated() {
85         synchronized (mLock) {
86             if (mIsClosed) {
87                 Slog.e(TAG, "Announcement aggregator is closed, it shouldn't receive callbacks");
88                 return;
89             }
90             List<Announcement> combined = new ArrayList<>();
91             for (ModuleWatcher watcher : mModuleWatchers) {
92                 combined.addAll(watcher.currentList);
93             }
94             try {
95                 mListener.onListUpdated(combined);
96             } catch (RemoteException ex) {
97                 Slog.e(TAG, "mListener.onListUpdated() failed: ", ex);
98             }
99         }
100     }
101 
watchModule(@onNull RadioModule module, @NonNull int[] enabledTypes)102     public void watchModule(@NonNull RadioModule module, @NonNull int[] enabledTypes) {
103         synchronized (mLock) {
104             if (mIsClosed) throw new IllegalStateException();
105 
106             ModuleWatcher watcher = new ModuleWatcher();
107             ICloseHandle closeHandle;
108             try {
109                 closeHandle = module.addAnnouncementListener(enabledTypes, watcher);
110             } catch (RemoteException ex) {
111                 Slog.e(TAG, "Failed to add announcement listener", ex);
112                 return;
113             }
114             watcher.setCloseHandle(closeHandle);
115             mModuleWatchers.add(watcher);
116         }
117     }
118 
119     @Override
close()120     public void close() throws RemoteException {
121         synchronized (mLock) {
122             if (mIsClosed) return;
123             mIsClosed = true;
124 
125             mListener.asBinder().unlinkToDeath(mDeathRecipient, 0);
126 
127             for (ModuleWatcher watcher : mModuleWatchers) {
128                 watcher.close();
129             }
130             mModuleWatchers.clear();
131         }
132     }
133 }
134