Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8fe25ff9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "CEC: AIDL Native Wrapper" am: d3ebddf5 am: c80d8857

parents 0a73eecb c80d8857
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -153,6 +153,8 @@ java_library_static {
        "android.hardware.health-translate-java",
        "android.hardware.light-V1-java",
        "android.hardware.tv.cec-V1.1-java",
        "android.hardware.tv.cec-V1-java",
        "android.hardware.tv.hdmi-V1-java",
        "android.hardware.weaver-V1.0-java",
        "android.hardware.biometrics.face-V1.0-java",
        "android.hardware.biometrics.fingerprint-V2.3-java",
+358 −21
Original line number Diff line number Diff line
@@ -19,20 +19,25 @@ package com.android.server.hdmi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.CecMessage;
import android.hardware.tv.cec.CecMessage;
import android.hardware.tv.cec.IHdmiCec;
import android.hardware.tv.cec.IHdmiCecCallback;
import android.hardware.tv.cec.V1_0.HotplugEvent;
import android.hardware.tv.cec.V1_0.IHdmiCec;
import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback;
import android.hardware.tv.cec.V1_0.IHdmiCecCallback;
import android.hardware.tv.cec.V1_0.OptionKey;
import android.hardware.tv.cec.V1_0.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.hardware.tv.hdmi.IHdmi;
import android.hardware.tv.hdmi.IHdmiCallback;
import android.icu.util.IllformedLocaleException;
import android.icu.util.ULocale;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.IHwBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.stats.hdmi.HdmiStatsEnums;
import android.util.Slog;

@@ -168,8 +173,14 @@ final class HdmiCecController {
     *         returns {@code null}.
     */
    static HdmiCecController create(HdmiControlService service, HdmiCecAtomWriter atomWriter) {
        HdmiCecController controller = createWithNativeWrapper(service, new NativeWrapperImpl11(),
                atomWriter);
        HdmiCecController controller =
                createWithNativeWrapper(service, new NativeWrapperImplAidl(), atomWriter);
        if (controller != null) {
            return controller;
        }
        HdmiLogger.warning("Unable to use CEC and HDMI AIDL HALs");

        controller = createWithNativeWrapper(service, new NativeWrapperImpl11(), atomWriter);
        if (controller != null) {
            return controller;
        }
@@ -360,16 +371,43 @@ final class HdmiCecController {
    }

    /**
     * Set an option to CEC HAL.
     * Configures the TV panel device wakeup behaviour in standby mode when it receives an OTP
     * (One Touch Play) from a source device.
     *
     * @param value If true, the TV device will wake up when OTP is received and if false, the TV
     *     device will not wake up for an OTP.
     */
    @ServiceThreadOnly
    void enableWakeupByOtp(boolean enabled) {
        assertRunOnServiceThread();
        HdmiLogger.debug("enableWakeupByOtp: %b", enabled);
        mNativeWrapperImpl.enableWakeupByOtp(enabled);
    }

    /**
     * Switch to enable or disable CEC on the device.
     *
     * @param flag key of option
     * @param enabled whether to enable/disable the given option.
     * @param value If true, the device will have all CEC functionalities and if false, the device
     *     will not perform any CEC functions.
     */
    @ServiceThreadOnly
    void setOption(int flag, boolean enabled) {
    void enableCec(boolean enabled) {
        assertRunOnServiceThread();
        HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
        mNativeWrapperImpl.nativeSetOption(flag, enabled);
        HdmiLogger.debug("enableCec: %b", enabled);
        mNativeWrapperImpl.enableCec(enabled);
    }

    /**
     * Configures the module that processes CEC messages - the Android framework or the HAL.
     *
     * @param value If true, the Android framework will actively process CEC messages and if false,
     *     only the HAL will process the CEC messages.
     */
    @ServiceThreadOnly
    void enableSystemCecControl(boolean enabled) {
        assertRunOnServiceThread();
        HdmiLogger.debug("enableSystemCecControl: %b", enabled);
        mNativeWrapperImpl.enableSystemCecControl(enabled);
    }

    /**
@@ -819,12 +857,233 @@ final class HdmiCecController {
        int nativeGetVersion();
        int nativeGetVendorId();
        HdmiPortInfo[] nativeGetPortInfos();
        void nativeSetOption(int flag, boolean enabled);

        void enableWakeupByOtp(boolean enabled);

        void enableCec(boolean enabled);

        void enableSystemCecControl(boolean enabled);

        void nativeSetLanguage(String language);
        void nativeEnableAudioReturnChannel(int port, boolean flag);
        boolean nativeIsConnected(int port);
    }

    private static final class NativeWrapperImplAidl
            implements NativeWrapper, IBinder.DeathRecipient {
        private IHdmiCec mHdmiCec;
        private IHdmi mHdmi;
        @Nullable private HdmiCecCallback mCallback;

        private final Object mLock = new Object();

        @Override
        public String nativeInit() {
            return connectToHal() ? mHdmiCec.toString() + " " + mHdmi.toString() : null;
        }

        boolean connectToHal() {
            mHdmiCec =
                    IHdmiCec.Stub.asInterface(
                            ServiceManager.getService(IHdmiCec.DESCRIPTOR + "/default"));
            if (mHdmiCec == null) {
                HdmiLogger.error("Could not initialize HDMI CEC AIDL HAL");
                return false;
            }
            try {
                mHdmiCec.asBinder().linkToDeath(this, 0);
            } catch (RemoteException e) {
                HdmiLogger.error("Couldn't link to death : ", e);
            }

            mHdmi =
                    IHdmi.Stub.asInterface(
                            ServiceManager.getService(IHdmi.DESCRIPTOR + "/default"));
            if (mHdmi == null) {
                HdmiLogger.error("Could not initialize HDMI AIDL HAL");
                return false;
            }
            try {
                mHdmi.asBinder().linkToDeath(this, 0);
            } catch (RemoteException e) {
                HdmiLogger.error("Couldn't link to death : ", e);
            }
            return true;
        }

        @Override
        public void binderDied() {
            // One of the services died, try to reconnect to both.
            mHdmiCec.asBinder().unlinkToDeath(this, 0);
            mHdmi.asBinder().unlinkToDeath(this, 0);
            HdmiLogger.error("HDMI or CEC service died, reconnecting");
            connectToHal();
            // Reconnect the callback
            if (mCallback != null) {
                setCallback(mCallback);
            }
        }

        @Override
        public void setCallback(HdmiCecCallback callback) {
            mCallback = callback;
            try {
                // Create an AIDL callback that can callback onCecMessage
                mHdmiCec.setCallback(new HdmiCecCallbackAidl(callback));
            } catch (RemoteException e) {
                HdmiLogger.error("Couldn't initialise tv.cec callback : ", e);
            }
            try {
                // Create an AIDL callback that can callback onHotplugEvent
                mHdmi.setCallback(new HdmiCallbackAidl(callback));
            } catch (RemoteException e) {
                HdmiLogger.error("Couldn't initialise tv.hdmi callback : ", e);
            }
        }

        @Override
        public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) {
            CecMessage message = new CecMessage();
            message.initiator = (byte) (srcAddress & 0xF);
            message.destination = (byte) (dstAddress & 0xF);
            message.body = body;
            try {
                return mHdmiCec.sendMessage(message);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to send CEC message : ", e);
                return SendMessageResult.FAIL;
            }
        }

        @Override
        public int nativeAddLogicalAddress(int logicalAddress) {
            try {
                return mHdmiCec.addLogicalAddress((byte) logicalAddress);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to add a logical address : ", e);
                return Result.FAILURE_INVALID_ARGS;
            }
        }

        @Override
        public void nativeClearLogicalAddress() {
            try {
                mHdmiCec.clearLogicalAddress();
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to clear logical address : ", e);
            }
        }

        @Override
        public int nativeGetPhysicalAddress() {
            try {
                return mHdmiCec.getPhysicalAddress();
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to get physical address : ", e);
                return INVALID_PHYSICAL_ADDRESS;
            }
        }

        @Override
        public int nativeGetVersion() {
            try {
                return mHdmiCec.getCecVersion();
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to get cec version : ", e);
                return Result.FAILURE_UNKNOWN;
            }
        }

        @Override
        public int nativeGetVendorId() {
            try {
                return mHdmiCec.getVendorId();
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to get vendor id : ", e);
                return Result.FAILURE_UNKNOWN;
            }
        }

        @Override
        public void enableWakeupByOtp(boolean enabled) {
            try {
                mHdmiCec.enableWakeupByOtp(enabled);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed call to enableWakeupByOtp : ", e);
            }
        }

        @Override
        public void enableCec(boolean enabled) {
            try {
                mHdmiCec.enableCec(enabled);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed call to enableCec : ", e);
            }
        }

        @Override
        public void enableSystemCecControl(boolean enabled) {
            try {
                mHdmiCec.enableSystemCecControl(enabled);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed call to enableSystemCecControl : ", e);
            }
        }

        @Override
        public void nativeSetLanguage(String language) {
            try {
                mHdmiCec.setLanguage(language);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to set language : ", e);
            }
        }

        @Override
        public void nativeEnableAudioReturnChannel(int port, boolean flag) {
            try {
                mHdmiCec.enableAudioReturnChannel(port, flag);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to enable/disable ARC : ", e);
            }
        }

        @Override
        public HdmiPortInfo[] nativeGetPortInfos() {
            try {
                android.hardware.tv.hdmi.HdmiPortInfo[] hdmiPortInfos = mHdmi.getPortInfo();
                HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.length];
                int i = 0;
                for (android.hardware.tv.hdmi.HdmiPortInfo portInfo : hdmiPortInfos) {
                    hdmiPortInfo[i] =
                            new HdmiPortInfo(
                                    portInfo.portId,
                                    portInfo.type,
                                    portInfo.physicalAddress,
                                    portInfo.cecSupported,
                                    false,
                                    portInfo.arcSupported);
                    i++;
                }
                return hdmiPortInfo;
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to get port information : ", e);
                return null;
            }
        }

        @Override
        public boolean nativeIsConnected(int port) {
            try {
                return mHdmi.isConnected(port);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to get connection info : ", e);
                return false;
            }
        }
    }

    private static final class NativeWrapperImpl11 implements NativeWrapper,
            IHwBinder.DeathRecipient, getPhysicalAddressCallback {
        private android.hardware.tv.cec.V1_1.IHdmiCec mHdmiCec;
@@ -975,8 +1234,7 @@ final class HdmiCecController {
            }
        }

        @Override
        public void nativeSetOption(int flag, boolean enabled) {
        private void nativeSetOption(int flag, boolean enabled) {
            try {
                mHdmiCec.setOption(flag, enabled);
            } catch (RemoteException e) {
@@ -984,6 +1242,21 @@ final class HdmiCecController {
            }
        }

        @Override
        public void enableWakeupByOtp(boolean enabled) {
            nativeSetOption(OptionKey.WAKEUP, enabled);
        }

        @Override
        public void enableCec(boolean enabled) {
            nativeSetOption(OptionKey.ENABLE_CEC, enabled);
        }

        @Override
        public void enableSystemCecControl(boolean enabled) {
            nativeSetOption(OptionKey.SYSTEM_CEC_CONTROL, enabled);
        }

        @Override
        public void nativeSetLanguage(String language) {
            try {
@@ -1028,7 +1301,7 @@ final class HdmiCecController {

        boolean connectToHal() {
            try {
                mHdmiCec = IHdmiCec.getService(true);
                mHdmiCec = android.hardware.tv.cec.V1_0.IHdmiCec.getService(true);
                try {
                    mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
                } catch (RemoteException e) {
@@ -1053,7 +1326,8 @@ final class HdmiCecController {

        @Override
        public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) {
            CecMessage message = new CecMessage();
            android.hardware.tv.cec.V1_0.CecMessage message =
                    new android.hardware.tv.cec.V1_0.CecMessage();
            message.initiator = srcAddress;
            message.destination = dstAddress;
            message.body = new ArrayList<>(body.length);
@@ -1141,8 +1415,7 @@ final class HdmiCecController {
            }
        }

        @Override
        public void nativeSetOption(int flag, boolean enabled) {
        private void nativeSetOption(int flag, boolean enabled) {
            try {
                mHdmiCec.setOption(flag, enabled);
            } catch (RemoteException e) {
@@ -1150,6 +1423,21 @@ final class HdmiCecController {
            }
        }

        @Override
        public void enableWakeupByOtp(boolean enabled) {
            nativeSetOption(OptionKey.WAKEUP, enabled);
        }

        @Override
        public void enableCec(boolean enabled) {
            nativeSetOption(OptionKey.ENABLE_CEC, enabled);
        }

        @Override
        public void enableSystemCecControl(boolean enabled) {
            nativeSetOption(OptionKey.SYSTEM_CEC_CONTROL, enabled);
        }

        @Override
        public void nativeSetLanguage(String language) {
            try {
@@ -1211,7 +1499,8 @@ final class HdmiCecController {
        }
    }

    private static final class HdmiCecCallback10 extends IHdmiCecCallback.Stub {
    private static final class HdmiCecCallback10
            extends android.hardware.tv.cec.V1_0.IHdmiCecCallback.Stub {
        private final HdmiCecCallback mHdmiCecCallback;

        HdmiCecCallback10(HdmiCecCallback hdmiCecCallback) {
@@ -1219,7 +1508,8 @@ final class HdmiCecController {
        }

        @Override
        public void onCecMessage(CecMessage message) throws RemoteException {
        public void onCecMessage(android.hardware.tv.cec.V1_0.CecMessage message)
                throws RemoteException {
            byte[] body = new byte[message.body.size()];
            for (int i = 0; i < message.body.size(); i++) {
                body[i] = message.body.get(i);
@@ -1252,7 +1542,8 @@ final class HdmiCecController {
        }

        @Override
        public void onCecMessage(CecMessage message) throws RemoteException {
        public void onCecMessage(android.hardware.tv.cec.V1_0.CecMessage message)
                throws RemoteException {
            byte[] body = new byte[message.body.size()];
            for (int i = 0; i < message.body.size(); i++) {
                body[i] = message.body.get(i);
@@ -1266,6 +1557,52 @@ final class HdmiCecController {
        }
    }

    private static final class HdmiCecCallbackAidl extends IHdmiCecCallback.Stub {
        private final HdmiCecCallback mHdmiCecCallback;

        HdmiCecCallbackAidl(HdmiCecCallback hdmiCecCallback) {
            mHdmiCecCallback = hdmiCecCallback;
        }

        @Override
        public void onCecMessage(CecMessage message) throws RemoteException {
            mHdmiCecCallback.onCecMessage(message.initiator, message.destination, message.body);
        }

        @Override
        public synchronized String getInterfaceHash() throws android.os.RemoteException {
            return IHdmiCecCallback.Stub.HASH;
        }

        @Override
        public int getInterfaceVersion() throws android.os.RemoteException {
            return IHdmiCecCallback.Stub.VERSION;
        }
    }

    private static final class HdmiCallbackAidl extends IHdmiCallback.Stub {
        private final HdmiCecCallback mHdmiCecCallback;

        HdmiCallbackAidl(HdmiCecCallback hdmiCecCallback) {
            mHdmiCecCallback = hdmiCecCallback;
        }

        @Override
        public void onHotplugEvent(boolean connected, int portId) throws RemoteException {
            mHdmiCecCallback.onHotplugEvent(portId, connected);
        }

        @Override
        public synchronized String getInterfaceHash() throws android.os.RemoteException {
            return IHdmiCallback.Stub.HASH;
        }

        @Override
        public int getInterfaceVersion() throws android.os.RemoteException {
            return IHdmiCallback.Stub.VERSION;
        }
    }

    public abstract static class Dumpable {
        protected final long mTime;

+23 −27
Original line number Diff line number Diff line
@@ -56,7 +56,6 @@ import android.hardware.hdmi.IHdmiMhlVendorCommandListener;
import android.hardware.hdmi.IHdmiRecordListener;
import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.hardware.tv.cec.V1_0.OptionKey;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
@@ -656,7 +655,7 @@ public class HdmiControlService extends SystemService {
        if (mHdmiControlEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED) {
            initializeCec(INITIATED_BY_BOOT_UP);
        } else {
            mCecController.setOption(OptionKey.ENABLE_CEC, false);
            mCecController.enableCec(false);
        }
        mMhlDevices = Collections.emptyList();

@@ -730,10 +729,11 @@ public class HdmiControlService extends SystemService {
                    @Override
                    public void onChange(String setting) {
                        if (isTvDeviceEnabled()) {
                            setCecOption(OptionKey.WAKEUP, tv().getAutoWakeup());
                            mCecController.enableWakeupByOtp(tv().getAutoWakeup());
                        }
                    }
                }, mServiceThreadExecutor);
                },
                mServiceThreadExecutor);
    }

    /** Returns true if the device screen is off */
@@ -854,7 +854,7 @@ public class HdmiControlService extends SystemService {
        mWakeUpMessageReceived = false;

        if (isTvDeviceEnabled()) {
            mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup());
            mCecController.enableWakeupByOtp(tv().getAutoWakeup());
        }
        int reason = -1;
        switch (initiatedBy) {
@@ -988,7 +988,7 @@ public class HdmiControlService extends SystemService {
        mCecVersion = Math.max(HdmiControlManager.HDMI_CEC_VERSION_1_4_B,
                Math.min(settingsCecVersion, supportedCecVersion));

        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
        mCecController.enableSystemCecControl(true);
        mCecController.setLanguage(mMenuLanguage);
        initializeLocalDevices(initiatedBy);
    }
@@ -3422,7 +3422,7 @@ public class HdmiControlService extends SystemService {
                device.onStandby(mStandbyMessageReceived, standbyAction);
            }
            if (!isAudioSystemDevice()) {
                mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false);
                mCecController.enableSystemCecControl(false);
                mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
            }
        }
@@ -3570,12 +3570,6 @@ public class HdmiControlService extends SystemService {
        runOnServiceThread(this::checkAndUpdateAbsoluteVolumeControlState);
    }

    @ServiceThreadOnly
    void setCecOption(int key, boolean value) {
        assertRunOnServiceThread();
        mCecController.setOption(key, value);
    }

    @ServiceThreadOnly
    void setControlEnabled(@HdmiControlManager.HdmiCecControl int enabled) {
        assertRunOnServiceThread();
@@ -3610,8 +3604,8 @@ public class HdmiControlService extends SystemService {

    @ServiceThreadOnly
    private void enableHdmiControlService() {
        mCecController.setOption(OptionKey.ENABLE_CEC, true);
        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
        mCecController.enableCec(true);
        mCecController.enableSystemCecControl(true);
        mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED);

        initializeCec(INITIATED_BY_ENABLE_CEC);
@@ -3619,15 +3613,17 @@ public class HdmiControlService extends SystemService {

    @ServiceThreadOnly
    private void disableHdmiControlService() {
        disableDevices(new PendingActionClearedCallback() {
        disableDevices(
                new PendingActionClearedCallback() {
                    @Override
                    public void onCleared(HdmiCecLocalDevice device) {
                        assertRunOnServiceThread();
                mCecController.flush(new Runnable() {
                        mCecController.flush(
                                new Runnable() {
                                    @Override
                                    public void run() {
                        mCecController.setOption(OptionKey.ENABLE_CEC, false);
                        mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false);
                                        mCecController.enableCec(false);
                                        mCecController.enableSystemCecControl(false);
                                        mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED);
                                        clearLocalDevices();
                                    }
+7 −1
Original line number Diff line number Diff line
@@ -118,7 +118,13 @@ final class FakeNativeWrapper implements NativeWrapper {
    }

    @Override
    public void nativeSetOption(int flag, boolean enabled) {}
    public void enableWakeupByOtp(boolean enabled) {}

    @Override
    public void enableCec(boolean enabled) {}

    @Override
    public void enableSystemCecControl(boolean enabled) {}

    @Override
    public void nativeSetLanguage(String language) {}