Loading services/core/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,8 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [ ":android.hardware.biometrics.face-V3-java-source", ":android.hardware.tv.hdmi.connection-V1-java-source", ":android.hardware.tv.hdmi.earc-V1-java-source", ":statslog-art-java-gen", ":statslog-contexthub-java-gen", ":services.core-sources", Loading Loading @@ -160,6 +162,7 @@ java_library_static { "android.hardware.tv.cec-V1.1-java", "android.hardware.tv.hdmi.cec-V1-java", "android.hardware.tv.hdmi.connection-V1-java", "android.hardware.tv.hdmi.earc-V1-java", "android.hardware.weaver-V1.0-java", "android.hardware.weaver-V2-java", "android.hardware.biometrics.face-V1.0-java", Loading services/core/java/com/android/server/hdmi/Constants.java +14 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.hdmi; import android.annotation.IntDef; import android.annotation.StringDef; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.tv.hdmi.connection.HpdSignal; import android.hardware.tv.hdmi.earc.IEArcStatus; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -599,10 +601,13 @@ final class Constants { }) @interface RcProfileSource {} static final int HDMI_EARC_STATUS_IDLE = 0; // IDLE1 static final int HDMI_EARC_STATUS_EARC_PENDING = 1; // DISC1 and DISC2 static final int HDMI_EARC_STATUS_ARC_PENDING = 2; // IDLE2 for ARC static final int HDMI_EARC_STATUS_EARC_CONNECTED = 3; // eARC connected static final int HDMI_EARC_STATUS_IDLE = IEArcStatus.STATUS_IDLE; // IDLE1 static final int HDMI_EARC_STATUS_EARC_PENDING = IEArcStatus.STATUS_EARC_PENDING; // DISC1 and DISC2 static final int HDMI_EARC_STATUS_ARC_PENDING = IEArcStatus.STATUS_ARC_PENDING; // IDLE2 for ARC static final int HDMI_EARC_STATUS_EARC_CONNECTED = IEArcStatus.STATUS_EARC_CONNECTED; // eARC connected @IntDef({ HDMI_EARC_STATUS_IDLE, HDMI_EARC_STATUS_EARC_PENDING, Loading @@ -611,8 +616,11 @@ final class Constants { }) @interface EarcStatus {} static final int HDMI_HPD_TYPE_PHYSICAL = 0; // Default. Physical hotplug signal. static final int HDMI_HPD_TYPE_STATUS_BIT = 1; // HDMI_HPD status bit. static final int HDMI_HPD_TYPE_PHYSICAL = HpdSignal.HDMI_HPD_PHYSICAL; // Default. Physical hotplug signal. static final int HDMI_HPD_TYPE_STATUS_BIT = HpdSignal.HDMI_HPD_STATUS_BIT; // HDMI_HPD status bit. @IntDef({ HDMI_HPD_TYPE_PHYSICAL, HDMI_HPD_TYPE_STATUS_BIT Loading services/core/java/com/android/server/hdmi/HdmiControlService.java +5 −0 Original line number Diff line number Diff line Loading @@ -930,6 +930,11 @@ public class HdmiControlService extends SystemService { mCecController = cecController; } @VisibleForTesting void setEarcController(HdmiEarcController earcController) { mEarcController = earcController; } @VisibleForTesting void setHdmiCecNetwork(HdmiCecNetwork hdmiCecNetwork) { mHdmiCecNetwork = hdmiCecNetwork; Loading services/core/java/com/android/server/hdmi/HdmiEarcController.java +145 −20 Original line number Diff line number Diff line Loading @@ -16,8 +16,14 @@ package com.android.server.hdmi; import android.hardware.tv.hdmi.earc.IEArc; import android.hardware.tv.hdmi.earc.IEArcCallback; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import com.android.internal.annotations.VisibleForTesting; Loading @@ -29,9 +35,109 @@ final class HdmiEarcController { private final HdmiControlService mService; private EArcNativeWrapper mEArcNativeWrapperImpl; protected interface EArcNativeWrapper { boolean nativeInit(); void nativeSetEArcEnabled(boolean enabled); boolean nativeIsEArcEnabled(); void nativeSetCallback(EarcAidlCallback callback); byte nativeGetState(int portId); byte[] nativeGetLastReportedAudioCapabilities(int portId); } private static final class EArcNativeWrapperImpl implements EArcNativeWrapper, IBinder.DeathRecipient { private IEArc mEArc; private EarcAidlCallback mEArcCallback; @Override public void binderDied() { mEArc.asBinder().unlinkToDeath(this, 0); connectToHal(); if (mEArcCallback != null) { nativeSetCallback(mEArcCallback); } } boolean connectToHal() { mEArc = IEArc.Stub.asInterface( ServiceManager.getService(IEArc.DESCRIPTOR + "/default")); if (mEArc == null) { return false; } try { mEArc.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { HdmiLogger.error("Couldn't link callback object: ", e); } return true; } @Override public boolean nativeInit() { return connectToHal(); } @Override public void nativeSetEArcEnabled(boolean enabled) { try { mEArc.setEArcEnabled(enabled); } catch (ServiceSpecificException sse) { HdmiLogger.error( "Could not set eARC enabled to " + enabled + ". Error: ", sse.errorCode); } catch (RemoteException re) { HdmiLogger.error("Could not set eARC enabled to " + enabled + ":. Exception: ", re); } } @Override public boolean nativeIsEArcEnabled() { try { return mEArc.isEArcEnabled(); } catch (RemoteException re) { HdmiLogger.error("Could not read if eARC is enabled. Exception: ", re); return false; } } @Override public void nativeSetCallback(EarcAidlCallback callback) { mEArcCallback = callback; try { mEArc.setCallback(callback); } catch (RemoteException re) { HdmiLogger.error("Could not set callback. Exception: ", re); } } @Override public byte nativeGetState(int portId) { try { return mEArc.getState(portId); } catch (RemoteException re) { HdmiLogger.error("Could not get eARC state. Exception: ", re); return -1; } } @Override public byte[] nativeGetLastReportedAudioCapabilities(int portId) { try { return mEArc.getLastReportedAudioCapabilities(portId); } catch (RemoteException re) { HdmiLogger.error( "Could not read last reported audio capabilities. Exception: ", re); return null; } } } // Private constructor. Use HdmiEarcController.create(). private HdmiEarcController(HdmiControlService service) { private HdmiEarcController(HdmiControlService service, EArcNativeWrapper nativeWrapper) { mService = service; mEArcNativeWrapperImpl = nativeWrapper; } /** Loading @@ -45,14 +151,29 @@ final class HdmiEarcController { * returns {@code null}. */ static HdmiEarcController create(HdmiControlService service) { // TODO add the native wrapper and return null if eARC HAL is not present. HdmiEarcController controller = new HdmiEarcController(service); controller.init(); return createWithNativeWrapper(service, new EArcNativeWrapperImpl()); } /** * A factory method with injection of native methods for testing. */ static HdmiEarcController createWithNativeWrapper(HdmiControlService service, EArcNativeWrapper nativeWrapper) { HdmiEarcController controller = new HdmiEarcController(service, nativeWrapper); if (!controller.init(nativeWrapper)) { HdmiLogger.warning("Could not connect to eARC AIDL HAL."); return null; } return controller; } private void init() { private boolean init(EArcNativeWrapper nativeWrapper) { if (nativeWrapper.nativeInit()) { mControlHandler = new Handler(mService.getServiceLooper()); mEArcNativeWrapperImpl.nativeSetCallback(new EarcAidlCallback()); return true; } return false; } private void assertRunOnServiceThread() { Loading @@ -73,9 +194,7 @@ final class HdmiEarcController { @HdmiAnnotations.ServiceThreadOnly void setEarcEnabled(boolean enabled) { assertRunOnServiceThread(); // Stub. // TODO: bind to native. // TODO: handle error return values here, with logging. mEArcNativeWrapperImpl.nativeSetEArcEnabled(enabled); } /** Loading @@ -86,23 +205,21 @@ final class HdmiEarcController { @HdmiAnnotations.ServiceThreadOnly @Constants.EarcStatus int getState(int portId) { // Stub. // TODO: bind to native. return Constants.HDMI_EARC_STATUS_IDLE; return mEArcNativeWrapperImpl.nativeGetState(portId); } /** * Ask the HAL to report the last eARC capabilities that the connected audio system reported. * * @return the raw eARC capabilities */ @HdmiAnnotations.ServiceThreadOnly byte[] getLastReportedCaps() { // Stub. TODO: bind to native. return new byte[] {}; byte[] getLastReportedCaps(int portId) { return mEArcNativeWrapperImpl.nativeGetLastReportedAudioCapabilities(portId); } final class EarcCallback { public void onStateChange(@Constants.EarcStatus int status, int portId) { final class EarcAidlCallback extends IEArcCallback.Stub { public void onStateChange(@Constants.EarcStatus byte status, int portId) { runOnServiceThread( () -> mService.handleEarcStateChange(status, portId)); } Loading @@ -111,7 +228,15 @@ final class HdmiEarcController { runOnServiceThread( () -> mService.handleEarcCapabilitiesReported(rawCapabilities, portId)); } @Override public synchronized String getInterfaceHash() throws RemoteException { return IEArcCallback.Stub.HASH; } // TODO: bind to native. @Override public int getInterfaceVersion() throws RemoteException { return IEArcCallback.Stub.VERSION; } } } services/tests/servicestests/src/com/android/server/hdmi/FakeEArcNativeWrapper.java 0 → 100644 +54 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.hdmi; import android.hardware.tv.hdmi.earc.IEArcStatus; final class FakeEArcNativeWrapper implements HdmiEarcController.EArcNativeWrapper { private static final String TAG = "FakeEArcNativeWrapper"; private boolean mIsEArcEnabled = true; @Override public boolean nativeInit() { return true; } @Override public void nativeSetEArcEnabled(boolean enabled) { mIsEArcEnabled = enabled; } @Override public boolean nativeIsEArcEnabled() { return mIsEArcEnabled; } @Override public void nativeSetCallback(HdmiEarcController.EarcAidlCallback callback) { } @Override public byte nativeGetState(int portId) { return IEArcStatus.STATUS_IDLE; } @Override public byte[] nativeGetLastReportedAudioCapabilities(int portId) { return new byte[] {}; } } Loading
services/core/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,8 @@ java_library_static { defaults: ["platform_service_defaults"], srcs: [ ":android.hardware.biometrics.face-V3-java-source", ":android.hardware.tv.hdmi.connection-V1-java-source", ":android.hardware.tv.hdmi.earc-V1-java-source", ":statslog-art-java-gen", ":statslog-contexthub-java-gen", ":services.core-sources", Loading Loading @@ -160,6 +162,7 @@ java_library_static { "android.hardware.tv.cec-V1.1-java", "android.hardware.tv.hdmi.cec-V1-java", "android.hardware.tv.hdmi.connection-V1-java", "android.hardware.tv.hdmi.earc-V1-java", "android.hardware.weaver-V1.0-java", "android.hardware.weaver-V2-java", "android.hardware.biometrics.face-V1.0-java", Loading
services/core/java/com/android/server/hdmi/Constants.java +14 −6 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.hdmi; import android.annotation.IntDef; import android.annotation.StringDef; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.tv.hdmi.connection.HpdSignal; import android.hardware.tv.hdmi.earc.IEArcStatus; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; Loading Loading @@ -599,10 +601,13 @@ final class Constants { }) @interface RcProfileSource {} static final int HDMI_EARC_STATUS_IDLE = 0; // IDLE1 static final int HDMI_EARC_STATUS_EARC_PENDING = 1; // DISC1 and DISC2 static final int HDMI_EARC_STATUS_ARC_PENDING = 2; // IDLE2 for ARC static final int HDMI_EARC_STATUS_EARC_CONNECTED = 3; // eARC connected static final int HDMI_EARC_STATUS_IDLE = IEArcStatus.STATUS_IDLE; // IDLE1 static final int HDMI_EARC_STATUS_EARC_PENDING = IEArcStatus.STATUS_EARC_PENDING; // DISC1 and DISC2 static final int HDMI_EARC_STATUS_ARC_PENDING = IEArcStatus.STATUS_ARC_PENDING; // IDLE2 for ARC static final int HDMI_EARC_STATUS_EARC_CONNECTED = IEArcStatus.STATUS_EARC_CONNECTED; // eARC connected @IntDef({ HDMI_EARC_STATUS_IDLE, HDMI_EARC_STATUS_EARC_PENDING, Loading @@ -611,8 +616,11 @@ final class Constants { }) @interface EarcStatus {} static final int HDMI_HPD_TYPE_PHYSICAL = 0; // Default. Physical hotplug signal. static final int HDMI_HPD_TYPE_STATUS_BIT = 1; // HDMI_HPD status bit. static final int HDMI_HPD_TYPE_PHYSICAL = HpdSignal.HDMI_HPD_PHYSICAL; // Default. Physical hotplug signal. static final int HDMI_HPD_TYPE_STATUS_BIT = HpdSignal.HDMI_HPD_STATUS_BIT; // HDMI_HPD status bit. @IntDef({ HDMI_HPD_TYPE_PHYSICAL, HDMI_HPD_TYPE_STATUS_BIT Loading
services/core/java/com/android/server/hdmi/HdmiControlService.java +5 −0 Original line number Diff line number Diff line Loading @@ -930,6 +930,11 @@ public class HdmiControlService extends SystemService { mCecController = cecController; } @VisibleForTesting void setEarcController(HdmiEarcController earcController) { mEarcController = earcController; } @VisibleForTesting void setHdmiCecNetwork(HdmiCecNetwork hdmiCecNetwork) { mHdmiCecNetwork = hdmiCecNetwork; Loading
services/core/java/com/android/server/hdmi/HdmiEarcController.java +145 −20 Original line number Diff line number Diff line Loading @@ -16,8 +16,14 @@ package com.android.server.hdmi; import android.hardware.tv.hdmi.earc.IEArc; import android.hardware.tv.hdmi.earc.IEArcCallback; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import com.android.internal.annotations.VisibleForTesting; Loading @@ -29,9 +35,109 @@ final class HdmiEarcController { private final HdmiControlService mService; private EArcNativeWrapper mEArcNativeWrapperImpl; protected interface EArcNativeWrapper { boolean nativeInit(); void nativeSetEArcEnabled(boolean enabled); boolean nativeIsEArcEnabled(); void nativeSetCallback(EarcAidlCallback callback); byte nativeGetState(int portId); byte[] nativeGetLastReportedAudioCapabilities(int portId); } private static final class EArcNativeWrapperImpl implements EArcNativeWrapper, IBinder.DeathRecipient { private IEArc mEArc; private EarcAidlCallback mEArcCallback; @Override public void binderDied() { mEArc.asBinder().unlinkToDeath(this, 0); connectToHal(); if (mEArcCallback != null) { nativeSetCallback(mEArcCallback); } } boolean connectToHal() { mEArc = IEArc.Stub.asInterface( ServiceManager.getService(IEArc.DESCRIPTOR + "/default")); if (mEArc == null) { return false; } try { mEArc.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { HdmiLogger.error("Couldn't link callback object: ", e); } return true; } @Override public boolean nativeInit() { return connectToHal(); } @Override public void nativeSetEArcEnabled(boolean enabled) { try { mEArc.setEArcEnabled(enabled); } catch (ServiceSpecificException sse) { HdmiLogger.error( "Could not set eARC enabled to " + enabled + ". Error: ", sse.errorCode); } catch (RemoteException re) { HdmiLogger.error("Could not set eARC enabled to " + enabled + ":. Exception: ", re); } } @Override public boolean nativeIsEArcEnabled() { try { return mEArc.isEArcEnabled(); } catch (RemoteException re) { HdmiLogger.error("Could not read if eARC is enabled. Exception: ", re); return false; } } @Override public void nativeSetCallback(EarcAidlCallback callback) { mEArcCallback = callback; try { mEArc.setCallback(callback); } catch (RemoteException re) { HdmiLogger.error("Could not set callback. Exception: ", re); } } @Override public byte nativeGetState(int portId) { try { return mEArc.getState(portId); } catch (RemoteException re) { HdmiLogger.error("Could not get eARC state. Exception: ", re); return -1; } } @Override public byte[] nativeGetLastReportedAudioCapabilities(int portId) { try { return mEArc.getLastReportedAudioCapabilities(portId); } catch (RemoteException re) { HdmiLogger.error( "Could not read last reported audio capabilities. Exception: ", re); return null; } } } // Private constructor. Use HdmiEarcController.create(). private HdmiEarcController(HdmiControlService service) { private HdmiEarcController(HdmiControlService service, EArcNativeWrapper nativeWrapper) { mService = service; mEArcNativeWrapperImpl = nativeWrapper; } /** Loading @@ -45,14 +151,29 @@ final class HdmiEarcController { * returns {@code null}. */ static HdmiEarcController create(HdmiControlService service) { // TODO add the native wrapper and return null if eARC HAL is not present. HdmiEarcController controller = new HdmiEarcController(service); controller.init(); return createWithNativeWrapper(service, new EArcNativeWrapperImpl()); } /** * A factory method with injection of native methods for testing. */ static HdmiEarcController createWithNativeWrapper(HdmiControlService service, EArcNativeWrapper nativeWrapper) { HdmiEarcController controller = new HdmiEarcController(service, nativeWrapper); if (!controller.init(nativeWrapper)) { HdmiLogger.warning("Could not connect to eARC AIDL HAL."); return null; } return controller; } private void init() { private boolean init(EArcNativeWrapper nativeWrapper) { if (nativeWrapper.nativeInit()) { mControlHandler = new Handler(mService.getServiceLooper()); mEArcNativeWrapperImpl.nativeSetCallback(new EarcAidlCallback()); return true; } return false; } private void assertRunOnServiceThread() { Loading @@ -73,9 +194,7 @@ final class HdmiEarcController { @HdmiAnnotations.ServiceThreadOnly void setEarcEnabled(boolean enabled) { assertRunOnServiceThread(); // Stub. // TODO: bind to native. // TODO: handle error return values here, with logging. mEArcNativeWrapperImpl.nativeSetEArcEnabled(enabled); } /** Loading @@ -86,23 +205,21 @@ final class HdmiEarcController { @HdmiAnnotations.ServiceThreadOnly @Constants.EarcStatus int getState(int portId) { // Stub. // TODO: bind to native. return Constants.HDMI_EARC_STATUS_IDLE; return mEArcNativeWrapperImpl.nativeGetState(portId); } /** * Ask the HAL to report the last eARC capabilities that the connected audio system reported. * * @return the raw eARC capabilities */ @HdmiAnnotations.ServiceThreadOnly byte[] getLastReportedCaps() { // Stub. TODO: bind to native. return new byte[] {}; byte[] getLastReportedCaps(int portId) { return mEArcNativeWrapperImpl.nativeGetLastReportedAudioCapabilities(portId); } final class EarcCallback { public void onStateChange(@Constants.EarcStatus int status, int portId) { final class EarcAidlCallback extends IEArcCallback.Stub { public void onStateChange(@Constants.EarcStatus byte status, int portId) { runOnServiceThread( () -> mService.handleEarcStateChange(status, portId)); } Loading @@ -111,7 +228,15 @@ final class HdmiEarcController { runOnServiceThread( () -> mService.handleEarcCapabilitiesReported(rawCapabilities, portId)); } @Override public synchronized String getInterfaceHash() throws RemoteException { return IEArcCallback.Stub.HASH; } // TODO: bind to native. @Override public int getInterfaceVersion() throws RemoteException { return IEArcCallback.Stub.VERSION; } } }
services/tests/servicestests/src/com/android/server/hdmi/FakeEArcNativeWrapper.java 0 → 100644 +54 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.hdmi; import android.hardware.tv.hdmi.earc.IEArcStatus; final class FakeEArcNativeWrapper implements HdmiEarcController.EArcNativeWrapper { private static final String TAG = "FakeEArcNativeWrapper"; private boolean mIsEArcEnabled = true; @Override public boolean nativeInit() { return true; } @Override public void nativeSetEArcEnabled(boolean enabled) { mIsEArcEnabled = enabled; } @Override public boolean nativeIsEArcEnabled() { return mIsEArcEnabled; } @Override public void nativeSetCallback(HdmiEarcController.EarcAidlCallback callback) { } @Override public byte nativeGetState(int portId) { return IEArcStatus.STATUS_IDLE; } @Override public byte[] nativeGetLastReportedAudioCapabilities(int portId) { return new byte[] {}; } }