Loading services/core/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,8 @@ java_library_static { "android.hardware.boot-V1.0-java", "android.hardware.boot-V1.1-java", "android.hardware.boot-V1.2-java", "android.hardware.broadcastradio-V2.0-java", "android.hardware.broadcastradio-V2.0-java", // HIDL "android.hardware.broadcastradio-V1-java", // AIDL "android.hardware.health-V1.0-java", // HIDL "android.hardware.health-V2.0-java", // HIDL "android.hardware.health-V2.1-java", // HIDL Loading services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java +6 −4 Original line number Diff line number Diff line Loading @@ -21,21 +21,23 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.radio.IRadioService; import android.util.Slog; import com.android.server.SystemService; import java.util.ArrayList; public class BroadcastRadioService extends SystemService { private static final String TAG = "BcRadioSrv"; private final IRadioService mServiceImpl; public BroadcastRadioService(Context context) { super(context); mServiceImpl = new BroadcastRadioServiceHidl(this); ArrayList<String> serviceNameList = IRadioServiceAidlImpl.getServicesNames(); mServiceImpl = serviceNameList.isEmpty() ? new IRadioServiceHidlImpl(this) : new IRadioServiceAidlImpl(this, serviceNameList); } @Override public void onStart() { Slog.v(TAG, "BroadcastRadioService onStart()"); publishBinderService(Context.RADIO_SERVICE, mServiceImpl.asBinder()); } Loading services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java 0 → 100644 +124 −0 Original line number Diff line number Diff line /** * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.broadcastradio; import android.hardware.broadcastradio.IBroadcastRadio; import android.hardware.radio.IAnnouncementListener; import android.hardware.radio.ICloseHandle; import android.hardware.radio.IRadioService; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.IndentingPrintWriter; import android.util.Log; import com.android.server.utils.Slogf; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * Wrapper for AIDL interface for BroadcastRadio HAL */ final class IRadioServiceAidlImpl extends IRadioService.Stub { private static final String TAG = "BcRadioSrvAidl"; private static final List<String> SERVICE_NAMES = Arrays.asList( IBroadcastRadio.DESCRIPTOR + "/amfm", IBroadcastRadio.DESCRIPTOR + "/dab"); private final com.android.server.broadcastradio.aidl.BroadcastRadioServiceImpl mHalAidl; private final BroadcastRadioService mService; /** * Gets names of all AIDL BroadcastRadio HAL services available. */ public static ArrayList<String> getServicesNames() { ArrayList<String> serviceList = new ArrayList<>(); for (int i = 0; i < SERVICE_NAMES.size(); i++) { IBinder serviceBinder = ServiceManager.waitForDeclaredService(SERVICE_NAMES.get(i)); if (serviceBinder != null) { serviceList.add(SERVICE_NAMES.get(i)); } } return serviceList; } IRadioServiceAidlImpl(BroadcastRadioService service, ArrayList<String> serviceList) { Slogf.i(TAG, "Initialize BroadcastRadioServiceAidl(%s)", service); mService = Objects.requireNonNull(service); mHalAidl = new com.android.server.broadcastradio.aidl.BroadcastRadioServiceImpl(serviceList); } @Override public List<RadioManager.ModuleProperties> listModules() { mService.enforcePolicyAccess(); return mHalAidl.listModules(); } @Override public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, boolean withAudio, ITunerCallback callback) throws RemoteException { if (isDebugEnabled()) { Slogf.d(TAG, "Opening module %d", moduleId); } mService.enforcePolicyAccess(); if (callback == null) { throw new IllegalArgumentException("Callback must not be null"); } return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback); } @Override public ICloseHandle addAnnouncementListener(int[] enabledTypes, IAnnouncementListener listener) { if (isDebugEnabled()) { Slogf.d(TAG, "Adding announcement listener for %s", Arrays.toString(enabledTypes)); } Objects.requireNonNull(enabledTypes); Objects.requireNonNull(listener); mService.enforcePolicyAccess(); return mHalAidl.addAnnouncementListener(enabledTypes, listener); } @Override protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter radioPrintWriter = new IndentingPrintWriter(printWriter); radioPrintWriter.printf("BroadcastRadioService\n"); radioPrintWriter.increaseIndent(); radioPrintWriter.printf("AIDL HAL:\n"); radioPrintWriter.increaseIndent(); mHalAidl.dumpInfo(radioPrintWriter); radioPrintWriter.decreaseIndent(); radioPrintWriter.decreaseIndent(); } private static boolean isDebugEnabled() { return Log.isLoggable(TAG, Log.DEBUG); } } services/core/java/com/android/server/broadcastradio/BroadcastRadioServiceHidl.java→services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ import java.util.OptionalInt; /** * Wrapper for HIDL interface for BroadcastRadio HAL */ final class BroadcastRadioServiceHidl extends IRadioService.Stub { final class IRadioServiceHidlImpl extends IRadioService.Stub { private static final String TAG = "BcRadioSrvHidl"; private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1; Loading @@ -52,7 +52,7 @@ final class BroadcastRadioServiceHidl extends IRadioService.Stub { private final BroadcastRadioService mService; private final List<RadioManager.ModuleProperties> mV1Modules; BroadcastRadioServiceHidl(BroadcastRadioService service) { IRadioServiceHidlImpl(BroadcastRadioService service) { mService = Objects.requireNonNull(service); mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock); mV1Modules = mHal1.loadModules(); Loading services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.broadcastradio.aidl; import android.annotation.Nullable; import android.hardware.radio.Announcement; import android.hardware.radio.IAnnouncementListener; import android.hardware.radio.ICloseHandle; import android.os.IBinder; import android.os.RemoteException; import android.util.IndentingPrintWriter; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.server.utils.Slogf; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * Announcement aggregator extending {@link ICloseHandle} to support broadcast radio announcement */ public final class AnnouncementAggregator extends ICloseHandle.Stub { private static final String TAG = "BcRadioAidlSrv.AnnAggr"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Object mLock; private final IAnnouncementListener mListener; private final IBinder.DeathRecipient mDeathRecipient = new DeathRecipient(); @GuardedBy("mLock") private final List<ModuleWatcher> mModuleWatchers = new ArrayList<>(); @GuardedBy("mLock") private boolean mIsClosed; /** * Constructs Announcement aggregator with AnnouncementListener of BroadcastRadio AIDL HAL. */ public AnnouncementAggregator(IAnnouncementListener listener, Object lock) { mListener = Objects.requireNonNull(listener, "listener cannot be null"); mLock = Objects.requireNonNull(lock, "lock cannot be null"); try { listener.asBinder().linkToDeath(mDeathRecipient, /* flags= */ 0); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } } private final class ModuleWatcher extends IAnnouncementListener.Stub { @Nullable private ICloseHandle mCloseHandle; public List<Announcement> mCurrentList = new ArrayList<>(); public void onListUpdated(List<Announcement> active) { if (DEBUG) { Slogf.d(TAG, "onListUpdate for %s", active); } mCurrentList = Objects.requireNonNull(active, "active cannot be null"); AnnouncementAggregator.this.onListUpdated(); } public void setCloseHandle(ICloseHandle closeHandle) { if (DEBUG) { Slogf.d(TAG, "Set close handle %s", closeHandle); } mCloseHandle = Objects.requireNonNull(closeHandle, "closeHandle cannot be null"); } public void close() throws RemoteException { if (DEBUG) { Slogf.d(TAG, "Close module watcher."); } if (mCloseHandle != null) mCloseHandle.close(); } public void dumpInfo(IndentingPrintWriter pw) { pw.printf("ModuleWatcher:\n"); pw.increaseIndent(); pw.printf("Close handle: %s\n", mCloseHandle); pw.printf("Current announcement list: %s\n", mCurrentList); pw.decreaseIndent(); } } private class DeathRecipient implements IBinder.DeathRecipient { public void binderDied() { try { close(); } catch (RemoteException ex) { Slogf.e(TAG, ex, "Cannot close Announcement aggregator for DeathRecipient"); } } } private void onListUpdated() { if (DEBUG) { Slogf.d(TAG, "onListUpdated()"); } synchronized (mLock) { if (mIsClosed) { Slogf.e(TAG, "Announcement aggregator is closed, it shouldn't receive callbacks"); return; } List<Announcement> combined = new ArrayList<>(mModuleWatchers.size()); for (int i = 0; i < mModuleWatchers.size(); i++) { combined.addAll(mModuleWatchers.get(i).mCurrentList); } try { mListener.onListUpdated(combined); } catch (RemoteException ex) { Slogf.e(TAG, ex, "mListener.onListUpdated() failed"); } } } /** * Watches the given RadioModule by adding Announcement Listener to it */ public void watchModule(RadioModule radioModule, int[] enabledTypes) { if (DEBUG) { Slogf.d(TAG, "Watch module for %s with enabled types %s", radioModule, Arrays.toString(enabledTypes)); } synchronized (mLock) { if (mIsClosed) { throw new IllegalStateException("Failed to watch module" + "since announcement aggregator has already been closed"); } ModuleWatcher watcher = new ModuleWatcher(); ICloseHandle closeHandle; try { closeHandle = radioModule.addAnnouncementListener(watcher, enabledTypes); } catch (RemoteException ex) { Slogf.e(TAG, ex, "Failed to add announcement listener"); return; } watcher.setCloseHandle(closeHandle); mModuleWatchers.add(watcher); } } @Override public void close() throws RemoteException { if (DEBUG) { Slogf.d(TAG, "Close watchModule"); } synchronized (mLock) { if (mIsClosed) { Slogf.w(TAG, "Announcement aggregator has already been closed."); return; } mListener.asBinder().unlinkToDeath(mDeathRecipient, /* flags= */ 0); for (int i = 0; i < mModuleWatchers.size(); i++) { ModuleWatcher moduleWatcher = mModuleWatchers.get(i); try { moduleWatcher.close(); } catch (Exception e) { Slogf.e(TAG, "Failed to close module watcher %s: %s", moduleWatcher, e); } } mModuleWatchers.clear(); mIsClosed = true; } } @Override protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter announcementPrintWriter = new IndentingPrintWriter(printWriter); announcementPrintWriter.printf("AnnouncementAggregator\n"); announcementPrintWriter.increaseIndent(); synchronized (mLock) { announcementPrintWriter.printf("Is session closed? %s\n", mIsClosed ? "Yes" : "No"); announcementPrintWriter.printf("Module Watchers [%d]:\n", mModuleWatchers.size()); announcementPrintWriter.increaseIndent(); for (int i = 0; i < mModuleWatchers.size(); i++) { mModuleWatchers.get(i).dumpInfo(announcementPrintWriter); } announcementPrintWriter.decreaseIndent(); } announcementPrintWriter.decreaseIndent(); } } Loading
services/core/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,8 @@ java_library_static { "android.hardware.boot-V1.0-java", "android.hardware.boot-V1.1-java", "android.hardware.boot-V1.2-java", "android.hardware.broadcastradio-V2.0-java", "android.hardware.broadcastradio-V2.0-java", // HIDL "android.hardware.broadcastradio-V1-java", // AIDL "android.hardware.health-V1.0-java", // HIDL "android.hardware.health-V2.0-java", // HIDL "android.hardware.health-V2.1-java", // HIDL Loading
services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java +6 −4 Original line number Diff line number Diff line Loading @@ -21,21 +21,23 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.radio.IRadioService; import android.util.Slog; import com.android.server.SystemService; import java.util.ArrayList; public class BroadcastRadioService extends SystemService { private static final String TAG = "BcRadioSrv"; private final IRadioService mServiceImpl; public BroadcastRadioService(Context context) { super(context); mServiceImpl = new BroadcastRadioServiceHidl(this); ArrayList<String> serviceNameList = IRadioServiceAidlImpl.getServicesNames(); mServiceImpl = serviceNameList.isEmpty() ? new IRadioServiceHidlImpl(this) : new IRadioServiceAidlImpl(this, serviceNameList); } @Override public void onStart() { Slog.v(TAG, "BroadcastRadioService onStart()"); publishBinderService(Context.RADIO_SERVICE, mServiceImpl.asBinder()); } Loading
services/core/java/com/android/server/broadcastradio/IRadioServiceAidlImpl.java 0 → 100644 +124 −0 Original line number Diff line number Diff line /** * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.broadcastradio; import android.hardware.broadcastradio.IBroadcastRadio; import android.hardware.radio.IAnnouncementListener; import android.hardware.radio.ICloseHandle; import android.hardware.radio.IRadioService; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.IndentingPrintWriter; import android.util.Log; import com.android.server.utils.Slogf; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * Wrapper for AIDL interface for BroadcastRadio HAL */ final class IRadioServiceAidlImpl extends IRadioService.Stub { private static final String TAG = "BcRadioSrvAidl"; private static final List<String> SERVICE_NAMES = Arrays.asList( IBroadcastRadio.DESCRIPTOR + "/amfm", IBroadcastRadio.DESCRIPTOR + "/dab"); private final com.android.server.broadcastradio.aidl.BroadcastRadioServiceImpl mHalAidl; private final BroadcastRadioService mService; /** * Gets names of all AIDL BroadcastRadio HAL services available. */ public static ArrayList<String> getServicesNames() { ArrayList<String> serviceList = new ArrayList<>(); for (int i = 0; i < SERVICE_NAMES.size(); i++) { IBinder serviceBinder = ServiceManager.waitForDeclaredService(SERVICE_NAMES.get(i)); if (serviceBinder != null) { serviceList.add(SERVICE_NAMES.get(i)); } } return serviceList; } IRadioServiceAidlImpl(BroadcastRadioService service, ArrayList<String> serviceList) { Slogf.i(TAG, "Initialize BroadcastRadioServiceAidl(%s)", service); mService = Objects.requireNonNull(service); mHalAidl = new com.android.server.broadcastradio.aidl.BroadcastRadioServiceImpl(serviceList); } @Override public List<RadioManager.ModuleProperties> listModules() { mService.enforcePolicyAccess(); return mHalAidl.listModules(); } @Override public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, boolean withAudio, ITunerCallback callback) throws RemoteException { if (isDebugEnabled()) { Slogf.d(TAG, "Opening module %d", moduleId); } mService.enforcePolicyAccess(); if (callback == null) { throw new IllegalArgumentException("Callback must not be null"); } return mHalAidl.openSession(moduleId, bandConfig, withAudio, callback); } @Override public ICloseHandle addAnnouncementListener(int[] enabledTypes, IAnnouncementListener listener) { if (isDebugEnabled()) { Slogf.d(TAG, "Adding announcement listener for %s", Arrays.toString(enabledTypes)); } Objects.requireNonNull(enabledTypes); Objects.requireNonNull(listener); mService.enforcePolicyAccess(); return mHalAidl.addAnnouncementListener(enabledTypes, listener); } @Override protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter radioPrintWriter = new IndentingPrintWriter(printWriter); radioPrintWriter.printf("BroadcastRadioService\n"); radioPrintWriter.increaseIndent(); radioPrintWriter.printf("AIDL HAL:\n"); radioPrintWriter.increaseIndent(); mHalAidl.dumpInfo(radioPrintWriter); radioPrintWriter.decreaseIndent(); radioPrintWriter.decreaseIndent(); } private static boolean isDebugEnabled() { return Log.isLoggable(TAG, Log.DEBUG); } }
services/core/java/com/android/server/broadcastradio/BroadcastRadioServiceHidl.java→services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java +2 −2 Original line number Diff line number Diff line Loading @@ -41,7 +41,7 @@ import java.util.OptionalInt; /** * Wrapper for HIDL interface for BroadcastRadio HAL */ final class BroadcastRadioServiceHidl extends IRadioService.Stub { final class IRadioServiceHidlImpl extends IRadioService.Stub { private static final String TAG = "BcRadioSrvHidl"; private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1; Loading @@ -52,7 +52,7 @@ final class BroadcastRadioServiceHidl extends IRadioService.Stub { private final BroadcastRadioService mService; private final List<RadioManager.ModuleProperties> mV1Modules; BroadcastRadioServiceHidl(BroadcastRadioService service) { IRadioServiceHidlImpl(BroadcastRadioService service) { mService = Objects.requireNonNull(service); mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock); mV1Modules = mHal1.loadModules(); Loading
services/core/java/com/android/server/broadcastradio/aidl/AnnouncementAggregator.java 0 → 100644 +213 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.broadcastradio.aidl; import android.annotation.Nullable; import android.hardware.radio.Announcement; import android.hardware.radio.IAnnouncementListener; import android.hardware.radio.ICloseHandle; import android.os.IBinder; import android.os.RemoteException; import android.util.IndentingPrintWriter; import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.server.utils.Slogf; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; /** * Announcement aggregator extending {@link ICloseHandle} to support broadcast radio announcement */ public final class AnnouncementAggregator extends ICloseHandle.Stub { private static final String TAG = "BcRadioAidlSrv.AnnAggr"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private final Object mLock; private final IAnnouncementListener mListener; private final IBinder.DeathRecipient mDeathRecipient = new DeathRecipient(); @GuardedBy("mLock") private final List<ModuleWatcher> mModuleWatchers = new ArrayList<>(); @GuardedBy("mLock") private boolean mIsClosed; /** * Constructs Announcement aggregator with AnnouncementListener of BroadcastRadio AIDL HAL. */ public AnnouncementAggregator(IAnnouncementListener listener, Object lock) { mListener = Objects.requireNonNull(listener, "listener cannot be null"); mLock = Objects.requireNonNull(lock, "lock cannot be null"); try { listener.asBinder().linkToDeath(mDeathRecipient, /* flags= */ 0); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } } private final class ModuleWatcher extends IAnnouncementListener.Stub { @Nullable private ICloseHandle mCloseHandle; public List<Announcement> mCurrentList = new ArrayList<>(); public void onListUpdated(List<Announcement> active) { if (DEBUG) { Slogf.d(TAG, "onListUpdate for %s", active); } mCurrentList = Objects.requireNonNull(active, "active cannot be null"); AnnouncementAggregator.this.onListUpdated(); } public void setCloseHandle(ICloseHandle closeHandle) { if (DEBUG) { Slogf.d(TAG, "Set close handle %s", closeHandle); } mCloseHandle = Objects.requireNonNull(closeHandle, "closeHandle cannot be null"); } public void close() throws RemoteException { if (DEBUG) { Slogf.d(TAG, "Close module watcher."); } if (mCloseHandle != null) mCloseHandle.close(); } public void dumpInfo(IndentingPrintWriter pw) { pw.printf("ModuleWatcher:\n"); pw.increaseIndent(); pw.printf("Close handle: %s\n", mCloseHandle); pw.printf("Current announcement list: %s\n", mCurrentList); pw.decreaseIndent(); } } private class DeathRecipient implements IBinder.DeathRecipient { public void binderDied() { try { close(); } catch (RemoteException ex) { Slogf.e(TAG, ex, "Cannot close Announcement aggregator for DeathRecipient"); } } } private void onListUpdated() { if (DEBUG) { Slogf.d(TAG, "onListUpdated()"); } synchronized (mLock) { if (mIsClosed) { Slogf.e(TAG, "Announcement aggregator is closed, it shouldn't receive callbacks"); return; } List<Announcement> combined = new ArrayList<>(mModuleWatchers.size()); for (int i = 0; i < mModuleWatchers.size(); i++) { combined.addAll(mModuleWatchers.get(i).mCurrentList); } try { mListener.onListUpdated(combined); } catch (RemoteException ex) { Slogf.e(TAG, ex, "mListener.onListUpdated() failed"); } } } /** * Watches the given RadioModule by adding Announcement Listener to it */ public void watchModule(RadioModule radioModule, int[] enabledTypes) { if (DEBUG) { Slogf.d(TAG, "Watch module for %s with enabled types %s", radioModule, Arrays.toString(enabledTypes)); } synchronized (mLock) { if (mIsClosed) { throw new IllegalStateException("Failed to watch module" + "since announcement aggregator has already been closed"); } ModuleWatcher watcher = new ModuleWatcher(); ICloseHandle closeHandle; try { closeHandle = radioModule.addAnnouncementListener(watcher, enabledTypes); } catch (RemoteException ex) { Slogf.e(TAG, ex, "Failed to add announcement listener"); return; } watcher.setCloseHandle(closeHandle); mModuleWatchers.add(watcher); } } @Override public void close() throws RemoteException { if (DEBUG) { Slogf.d(TAG, "Close watchModule"); } synchronized (mLock) { if (mIsClosed) { Slogf.w(TAG, "Announcement aggregator has already been closed."); return; } mListener.asBinder().unlinkToDeath(mDeathRecipient, /* flags= */ 0); for (int i = 0; i < mModuleWatchers.size(); i++) { ModuleWatcher moduleWatcher = mModuleWatchers.get(i); try { moduleWatcher.close(); } catch (Exception e) { Slogf.e(TAG, "Failed to close module watcher %s: %s", moduleWatcher, e); } } mModuleWatchers.clear(); mIsClosed = true; } } @Override protected void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { IndentingPrintWriter announcementPrintWriter = new IndentingPrintWriter(printWriter); announcementPrintWriter.printf("AnnouncementAggregator\n"); announcementPrintWriter.increaseIndent(); synchronized (mLock) { announcementPrintWriter.printf("Is session closed? %s\n", mIsClosed ? "Yes" : "No"); announcementPrintWriter.printf("Module Watchers [%d]:\n", mModuleWatchers.size()); announcementPrintWriter.increaseIndent(); for (int i = 0; i < mModuleWatchers.size(); i++) { mModuleWatchers.get(i).dumpInfo(announcementPrintWriter); } announcementPrintWriter.decreaseIndent(); } announcementPrintWriter.decreaseIndent(); } }