Loading services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java +5 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,11 @@ public class AnnouncementAggregator extends ICloseHandle.Stub { for (ModuleWatcher watcher : mModuleWatchers) { combined.addAll(watcher.currentList); } TunerCallback.dispatch(() -> mListener.onListUpdated(combined)); try { mListener.onListUpdated(combined); } catch (RemoteException ex) { Slog.e(TAG, "mListener.onListUpdated() failed: ", ex); } } } Loading services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +8 −23 Original line number Diff line number Diff line Loading @@ -54,13 +54,6 @@ public class BroadcastRadioService { @GuardedBy("mLock") private final Map<Integer, RadioModule> mModules = new HashMap<>(); // Map from module ID to TunerSession created by openSession(). // // Because this service currently implements a 1 AIDL to 1 HAL policy, mTunerSessions is used to // enforce the "aggresive open" policy mandated for IBroadcastRadio.openSession(). In the // future, this solution will be replaced with a multiple-AIDL to 1 HAL implementation. private final Map<Integer, TunerSession> mTunerSessions = new HashMap<>(); private IServiceNotification.Stub mServiceListener = new IServiceNotification.Stub() { @Override public void onRegistration(String fqName, String serviceName, boolean preexisting) { Loading @@ -81,8 +74,10 @@ public class BroadcastRadioService { } Slog.v(TAG, "loaded broadcast radio module " + moduleId + ": " + serviceName + " (HAL 2.0)"); closeTunerSessionLocked(moduleId); mModules.put(moduleId, module); RadioModule prevModule = mModules.put(moduleId, module); if (prevModule != null) { prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE); } if (newService) { mServiceNameToModuleIdMap.put(serviceName, moduleId); Loading @@ -105,8 +100,10 @@ public class BroadcastRadioService { Slog.v(TAG, "serviceDied(" + cookie + ")"); synchronized (mLock) { int moduleId = (int) cookie; mModules.remove(moduleId); closeTunerSessionLocked(moduleId); RadioModule prevModule = mModules.remove(moduleId); if (prevModule != null) { prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE); } for (Map.Entry<String, Integer> entry : mServiceNameToModuleIdMap.entrySet()) { if (entry.getValue() == moduleId) { Loading Loading @@ -166,13 +163,9 @@ public class BroadcastRadioService { if (module == null) { throw new IllegalArgumentException("Invalid module ID"); } closeTunerSessionLocked(moduleId); } TunerSession tunerSession = module.openSession(callback); synchronized (mLock) { mTunerSessions.put(moduleId, tunerSession); } if (legacyConfig != null) { tunerSession.setConfiguration(legacyConfig); } Loading @@ -198,12 +191,4 @@ public class BroadcastRadioService { } return aggregator; } private void closeTunerSessionLocked(int moduleId) { TunerSession tunerSession = mTunerSessions.remove(moduleId); if (tunerSession != null) { Slog.d(TAG, "Closing previous TunerSession"); tunerSession.close(RadioTuner.ERROR_HARDWARE_FAILURE); } } } services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +141 −12 Original line number Diff line number Diff line Loading @@ -26,16 +26,26 @@ import android.hardware.broadcastradio.V2_0.DabTableEntry; import android.hardware.broadcastradio.V2_0.IAnnouncementListener; import android.hardware.broadcastradio.V2_0.IBroadcastRadio; import android.hardware.broadcastradio.V2_0.ICloseHandle; import android.hardware.broadcastradio.V2_0.ITunerCallback; import android.hardware.broadcastradio.V2_0.ITunerSession; import android.hardware.broadcastradio.V2_0.ProgramInfo; import android.hardware.broadcastradio.V2_0.ProgramListChunk; import android.hardware.broadcastradio.V2_0.ProgramSelector; import android.hardware.broadcastradio.V2_0.Result; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.RadioManager; import android.os.DeadObjectException; import android.os.RemoteException; import android.util.MutableInt; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; class RadioModule { Loading @@ -44,8 +54,63 @@ class RadioModule { @NonNull private final IBroadcastRadio mService; @NonNull public final RadioManager.ModuleProperties mProperties; private final Object mLock = new Object(); @GuardedBy("mLock") private ITunerSession mHalTunerSession; // Tracks antenna state reported by HAL (if any). @GuardedBy("mLock") private Boolean mAntennaConnected = null; @GuardedBy("mLock") private RadioManager.ProgramInfo mProgramInfo = null; // Callback registered with the HAL to relay callbacks to AIDL clients. private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() { @Override public void onTuneFailed(int result, ProgramSelector programSelector) { fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal( programSelector))); } @Override public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) { RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo); synchronized (mLock) { mProgramInfo = programInfo; fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo)); } } @Override public void onProgramListUpdated(ProgramListChunk programListChunk) { // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan // back out to clients. fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal( programListChunk))); } @Override public void onAntennaStateChange(boolean connected) { synchronized (mLock) { mAntennaConnected = connected; fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected)); } } @Override public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); } }; // Collection of active AIDL tuner sessions created through openSession(). @GuardedBy("mLock") private final Set<TunerSession> mAidlTunerSessions = new HashSet<>(); private RadioModule(@NonNull IBroadcastRadio service, @NonNull RadioManager.ModuleProperties properties) { @NonNull RadioManager.ModuleProperties properties) throws RemoteException { mProperties = Objects.requireNonNull(properties); mService = Objects.requireNonNull(service); } Loading Loading @@ -81,21 +146,85 @@ class RadioModule { public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) throws RemoteException { TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb)); synchronized (mLock) { if (mHalTunerSession == null) { Mutable<ITunerSession> hwSession = new Mutable<>(); MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR); synchronized (mService) { mService.openSession(cb, (result, session) -> { mService.openSession(mHalTunerCallback, (result, session) -> { Convert.throwOnError("openSession", result); hwSession.value = session; halResult.value = result; }); mHalTunerSession = Objects.requireNonNull(hwSession.value); } TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb); mAidlTunerSessions.add(tunerSession); // Propagate state to new client. Note: These callbacks are invoked while holding mLock // to prevent race conditions with new callbacks from the HAL. if (mAntennaConnected != null) { userCb.onAntennaState(mAntennaConnected); } if (mProgramInfo != null) { userCb.onCurrentProgramInfoChanged(mProgramInfo); } return tunerSession; } } public void closeSessions(Integer error) { // Copy the contents of mAidlTunerSessions into a local array because TunerSession.close() // must be called without mAidlTunerSessions locked because it can call // onTunerSessionClosed(). TunerSession[] tunerSessions; synchronized (mLock) { tunerSessions = new TunerSession[mAidlTunerSessions.size()]; mAidlTunerSessions.toArray(tunerSessions); mAidlTunerSessions.clear(); } for (TunerSession tunerSession : tunerSessions) { tunerSession.close(error); } } void onTunerSessionClosed(TunerSession tunerSession) { synchronized (mLock) { mAidlTunerSessions.remove(tunerSession); if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) { Slog.v(TAG, "closing HAL tuner session"); try { mHalTunerSession.close(); } catch (RemoteException ex) { Slog.e(TAG, "mHalTunerSession.close() failed: ", ex); } mHalTunerSession = null; } } } interface AidlCallbackRunnable { void run(android.hardware.radio.ITunerCallback callback) throws RemoteException; } Convert.throwOnError("openSession", halResult.value); Objects.requireNonNull(hwSession.value); // Invokes runnable with each TunerSession currently open. void fanoutAidlCallback(AidlCallbackRunnable runnable) { synchronized (mLock) { fanoutAidlCallbackLocked(runnable); } } return new TunerSession(this, hwSession.value, cb); private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { for (TunerSession tunerSession : mAidlTunerSessions) { try { runnable.run(tunerSession.mCallback); } catch (DeadObjectException ex) { // The other side died without calling close(), so just purge it from our // records. Slog.e(TAG, "Removing dead TunerSession"); mAidlTunerSessions.remove(tunerSession); } catch (RemoteException ex) { Slog.e(TAG, "Failed to invoke ITunerCallback: ", ex); } } } public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes, Loading services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.javadeleted 100644 → 0 +0 −76 Original line number Diff line number Diff line /** * Copyright (C) 2017 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.hal2; import android.annotation.NonNull; import android.hardware.broadcastradio.V2_0.ITunerCallback; import android.hardware.broadcastradio.V2_0.ProgramInfo; import android.hardware.broadcastradio.V2_0.ProgramListChunk; import android.hardware.broadcastradio.V2_0.ProgramSelector; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.os.RemoteException; import android.util.Slog; import java.util.ArrayList; import java.util.Objects; class TunerCallback extends ITunerCallback.Stub { private static final String TAG = "BcRadio2Srv.cb"; final android.hardware.radio.ITunerCallback mClientCb; interface RunnableThrowingRemoteException { void run() throws RemoteException; } TunerCallback(@NonNull android.hardware.radio.ITunerCallback clientCallback) { mClientCb = Objects.requireNonNull(clientCallback); } static void dispatch(RunnableThrowingRemoteException func) { try { func.run(); } catch (RemoteException ex) { Slog.e(TAG, "callback call failed", ex); } } @Override public void onTuneFailed(int result, ProgramSelector selector) { dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector))); } @Override public void onCurrentProgramInfoChanged(ProgramInfo info) { dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info))); } @Override public void onProgramListUpdated(ProgramListChunk chunk) { dispatch(() -> mClientCb.onProgramListUpdated(Convert.programListChunkFromHal(chunk))); } @Override public void onAntennaStateChange(boolean connected) { dispatch(() -> mClientCb.onAntennaState(connected)); } @Override public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); } } services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +10 −5 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ class TunerSession extends ITuner.Stub { private final RadioModule mModule; private final ITunerSession mHwSession; private final TunerCallback mCallback; final android.hardware.radio.ITunerCallback mCallback; private boolean mIsClosed = false; private boolean mIsMuted = false; Loading @@ -51,7 +51,7 @@ class TunerSession extends ITuner.Stub { private RadioManager.BandConfig mDummyConfig = null; TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession, @NonNull TunerCallback callback) { @NonNull android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(module); mHwSession = Objects.requireNonNull(hwSession); mCallback = Objects.requireNonNull(callback); Loading @@ -73,9 +73,14 @@ class TunerSession extends ITuner.Stub { synchronized (mLock) { if (mIsClosed) return; if (error != null) { TunerCallback.dispatch(() -> mCallback.mClientCb.onError(error)); try { mCallback.onError(error); } catch (RemoteException ex) { Slog.w(TAG, "mCallback.onError() failed: ", ex); } } mIsClosed = true; mModule.onTunerSessionClosed(this); } } Loading @@ -96,7 +101,7 @@ class TunerSession extends ITuner.Stub { checkNotClosedLocked(); mDummyConfig = Objects.requireNonNull(config); Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x"); TunerCallback.dispatch(() -> mCallback.mClientCb.onConfigurationChanged(config)); mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config)); } } Loading Loading @@ -174,7 +179,7 @@ class TunerSession extends ITuner.Stub { @Override public boolean startBackgroundScan() { Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x"); TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete()); mModule.fanoutAidlCallback(cb -> cb.onBackgroundScanComplete()); return true; } Loading Loading
services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java +5 −1 Original line number Diff line number Diff line Loading @@ -90,7 +90,11 @@ public class AnnouncementAggregator extends ICloseHandle.Stub { for (ModuleWatcher watcher : mModuleWatchers) { combined.addAll(watcher.currentList); } TunerCallback.dispatch(() -> mListener.onListUpdated(combined)); try { mListener.onListUpdated(combined); } catch (RemoteException ex) { Slog.e(TAG, "mListener.onListUpdated() failed: ", ex); } } } Loading
services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +8 −23 Original line number Diff line number Diff line Loading @@ -54,13 +54,6 @@ public class BroadcastRadioService { @GuardedBy("mLock") private final Map<Integer, RadioModule> mModules = new HashMap<>(); // Map from module ID to TunerSession created by openSession(). // // Because this service currently implements a 1 AIDL to 1 HAL policy, mTunerSessions is used to // enforce the "aggresive open" policy mandated for IBroadcastRadio.openSession(). In the // future, this solution will be replaced with a multiple-AIDL to 1 HAL implementation. private final Map<Integer, TunerSession> mTunerSessions = new HashMap<>(); private IServiceNotification.Stub mServiceListener = new IServiceNotification.Stub() { @Override public void onRegistration(String fqName, String serviceName, boolean preexisting) { Loading @@ -81,8 +74,10 @@ public class BroadcastRadioService { } Slog.v(TAG, "loaded broadcast radio module " + moduleId + ": " + serviceName + " (HAL 2.0)"); closeTunerSessionLocked(moduleId); mModules.put(moduleId, module); RadioModule prevModule = mModules.put(moduleId, module); if (prevModule != null) { prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE); } if (newService) { mServiceNameToModuleIdMap.put(serviceName, moduleId); Loading @@ -105,8 +100,10 @@ public class BroadcastRadioService { Slog.v(TAG, "serviceDied(" + cookie + ")"); synchronized (mLock) { int moduleId = (int) cookie; mModules.remove(moduleId); closeTunerSessionLocked(moduleId); RadioModule prevModule = mModules.remove(moduleId); if (prevModule != null) { prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE); } for (Map.Entry<String, Integer> entry : mServiceNameToModuleIdMap.entrySet()) { if (entry.getValue() == moduleId) { Loading Loading @@ -166,13 +163,9 @@ public class BroadcastRadioService { if (module == null) { throw new IllegalArgumentException("Invalid module ID"); } closeTunerSessionLocked(moduleId); } TunerSession tunerSession = module.openSession(callback); synchronized (mLock) { mTunerSessions.put(moduleId, tunerSession); } if (legacyConfig != null) { tunerSession.setConfiguration(legacyConfig); } Loading @@ -198,12 +191,4 @@ public class BroadcastRadioService { } return aggregator; } private void closeTunerSessionLocked(int moduleId) { TunerSession tunerSession = mTunerSessions.remove(moduleId); if (tunerSession != null) { Slog.d(TAG, "Closing previous TunerSession"); tunerSession.close(RadioTuner.ERROR_HARDWARE_FAILURE); } } }
services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +141 −12 Original line number Diff line number Diff line Loading @@ -26,16 +26,26 @@ import android.hardware.broadcastradio.V2_0.DabTableEntry; import android.hardware.broadcastradio.V2_0.IAnnouncementListener; import android.hardware.broadcastradio.V2_0.IBroadcastRadio; import android.hardware.broadcastradio.V2_0.ICloseHandle; import android.hardware.broadcastradio.V2_0.ITunerCallback; import android.hardware.broadcastradio.V2_0.ITunerSession; import android.hardware.broadcastradio.V2_0.ProgramInfo; import android.hardware.broadcastradio.V2_0.ProgramListChunk; import android.hardware.broadcastradio.V2_0.ProgramSelector; import android.hardware.broadcastradio.V2_0.Result; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.RadioManager; import android.os.DeadObjectException; import android.os.RemoteException; import android.util.MutableInt; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; class RadioModule { Loading @@ -44,8 +54,63 @@ class RadioModule { @NonNull private final IBroadcastRadio mService; @NonNull public final RadioManager.ModuleProperties mProperties; private final Object mLock = new Object(); @GuardedBy("mLock") private ITunerSession mHalTunerSession; // Tracks antenna state reported by HAL (if any). @GuardedBy("mLock") private Boolean mAntennaConnected = null; @GuardedBy("mLock") private RadioManager.ProgramInfo mProgramInfo = null; // Callback registered with the HAL to relay callbacks to AIDL clients. private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() { @Override public void onTuneFailed(int result, ProgramSelector programSelector) { fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal( programSelector))); } @Override public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) { RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo); synchronized (mLock) { mProgramInfo = programInfo; fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo)); } } @Override public void onProgramListUpdated(ProgramListChunk programListChunk) { // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan // back out to clients. fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal( programListChunk))); } @Override public void onAntennaStateChange(boolean connected) { synchronized (mLock) { mAntennaConnected = connected; fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected)); } } @Override public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); } }; // Collection of active AIDL tuner sessions created through openSession(). @GuardedBy("mLock") private final Set<TunerSession> mAidlTunerSessions = new HashSet<>(); private RadioModule(@NonNull IBroadcastRadio service, @NonNull RadioManager.ModuleProperties properties) { @NonNull RadioManager.ModuleProperties properties) throws RemoteException { mProperties = Objects.requireNonNull(properties); mService = Objects.requireNonNull(service); } Loading Loading @@ -81,21 +146,85 @@ class RadioModule { public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) throws RemoteException { TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb)); synchronized (mLock) { if (mHalTunerSession == null) { Mutable<ITunerSession> hwSession = new Mutable<>(); MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR); synchronized (mService) { mService.openSession(cb, (result, session) -> { mService.openSession(mHalTunerCallback, (result, session) -> { Convert.throwOnError("openSession", result); hwSession.value = session; halResult.value = result; }); mHalTunerSession = Objects.requireNonNull(hwSession.value); } TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb); mAidlTunerSessions.add(tunerSession); // Propagate state to new client. Note: These callbacks are invoked while holding mLock // to prevent race conditions with new callbacks from the HAL. if (mAntennaConnected != null) { userCb.onAntennaState(mAntennaConnected); } if (mProgramInfo != null) { userCb.onCurrentProgramInfoChanged(mProgramInfo); } return tunerSession; } } public void closeSessions(Integer error) { // Copy the contents of mAidlTunerSessions into a local array because TunerSession.close() // must be called without mAidlTunerSessions locked because it can call // onTunerSessionClosed(). TunerSession[] tunerSessions; synchronized (mLock) { tunerSessions = new TunerSession[mAidlTunerSessions.size()]; mAidlTunerSessions.toArray(tunerSessions); mAidlTunerSessions.clear(); } for (TunerSession tunerSession : tunerSessions) { tunerSession.close(error); } } void onTunerSessionClosed(TunerSession tunerSession) { synchronized (mLock) { mAidlTunerSessions.remove(tunerSession); if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) { Slog.v(TAG, "closing HAL tuner session"); try { mHalTunerSession.close(); } catch (RemoteException ex) { Slog.e(TAG, "mHalTunerSession.close() failed: ", ex); } mHalTunerSession = null; } } } interface AidlCallbackRunnable { void run(android.hardware.radio.ITunerCallback callback) throws RemoteException; } Convert.throwOnError("openSession", halResult.value); Objects.requireNonNull(hwSession.value); // Invokes runnable with each TunerSession currently open. void fanoutAidlCallback(AidlCallbackRunnable runnable) { synchronized (mLock) { fanoutAidlCallbackLocked(runnable); } } return new TunerSession(this, hwSession.value, cb); private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { for (TunerSession tunerSession : mAidlTunerSessions) { try { runnable.run(tunerSession.mCallback); } catch (DeadObjectException ex) { // The other side died without calling close(), so just purge it from our // records. Slog.e(TAG, "Removing dead TunerSession"); mAidlTunerSessions.remove(tunerSession); } catch (RemoteException ex) { Slog.e(TAG, "Failed to invoke ITunerCallback: ", ex); } } } public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes, Loading
services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.javadeleted 100644 → 0 +0 −76 Original line number Diff line number Diff line /** * Copyright (C) 2017 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.hal2; import android.annotation.NonNull; import android.hardware.broadcastradio.V2_0.ITunerCallback; import android.hardware.broadcastradio.V2_0.ProgramInfo; import android.hardware.broadcastradio.V2_0.ProgramListChunk; import android.hardware.broadcastradio.V2_0.ProgramSelector; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.os.RemoteException; import android.util.Slog; import java.util.ArrayList; import java.util.Objects; class TunerCallback extends ITunerCallback.Stub { private static final String TAG = "BcRadio2Srv.cb"; final android.hardware.radio.ITunerCallback mClientCb; interface RunnableThrowingRemoteException { void run() throws RemoteException; } TunerCallback(@NonNull android.hardware.radio.ITunerCallback clientCallback) { mClientCb = Objects.requireNonNull(clientCallback); } static void dispatch(RunnableThrowingRemoteException func) { try { func.run(); } catch (RemoteException ex) { Slog.e(TAG, "callback call failed", ex); } } @Override public void onTuneFailed(int result, ProgramSelector selector) { dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector))); } @Override public void onCurrentProgramInfoChanged(ProgramInfo info) { dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info))); } @Override public void onProgramListUpdated(ProgramListChunk chunk) { dispatch(() -> mClientCb.onProgramListUpdated(Convert.programListChunkFromHal(chunk))); } @Override public void onAntennaStateChange(boolean connected) { dispatch(() -> mClientCb.onAntennaState(connected)); } @Override public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) { dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters))); } }
services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +10 −5 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ class TunerSession extends ITuner.Stub { private final RadioModule mModule; private final ITunerSession mHwSession; private final TunerCallback mCallback; final android.hardware.radio.ITunerCallback mCallback; private boolean mIsClosed = false; private boolean mIsMuted = false; Loading @@ -51,7 +51,7 @@ class TunerSession extends ITuner.Stub { private RadioManager.BandConfig mDummyConfig = null; TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession, @NonNull TunerCallback callback) { @NonNull android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(module); mHwSession = Objects.requireNonNull(hwSession); mCallback = Objects.requireNonNull(callback); Loading @@ -73,9 +73,14 @@ class TunerSession extends ITuner.Stub { synchronized (mLock) { if (mIsClosed) return; if (error != null) { TunerCallback.dispatch(() -> mCallback.mClientCb.onError(error)); try { mCallback.onError(error); } catch (RemoteException ex) { Slog.w(TAG, "mCallback.onError() failed: ", ex); } } mIsClosed = true; mModule.onTunerSessionClosed(this); } } Loading @@ -96,7 +101,7 @@ class TunerSession extends ITuner.Stub { checkNotClosedLocked(); mDummyConfig = Objects.requireNonNull(config); Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x"); TunerCallback.dispatch(() -> mCallback.mClientCb.onConfigurationChanged(config)); mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config)); } } Loading Loading @@ -174,7 +179,7 @@ class TunerSession extends ITuner.Stub { @Override public boolean startBackgroundScan() { Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x"); TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete()); mModule.fanoutAidlCallback(cb -> cb.onBackgroundScanComplete()); return true; } Loading