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

Commit 2f0e16a8 authored by Shraddha Basantwani's avatar Shraddha Basantwani
Browse files

Use generated Java bindings for CEC HAL

Replace usage of JNI methods with Java bindings.

Bug: 150290661
Test: run cts -m CtsServicesHostTestCases
Test: adb shell dumpsys hdmi_control
Change-Id: I43c72ab6cc203da1d935bd51fc0fd11b930255ce
parent bf7cb1ca
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ java_library_static {
        "services.net",
        "android.hardware.light-V2.0-java",
        "android.hardware.power-V1.0-java",
        "android.hardware.tv.cec-V1.0-java",
        "android.hardware.vibrator-java",
        "android.net.ipsec.ike.stubs.module_libs_api",
        "app-compat-annotations",
@@ -46,6 +45,7 @@ java_library_static {
        "android.hardware.health-V2.0-java",
        "android.hardware.health-V2.1-java",
        "android.hardware.light-java",
        "android.hardware.tv.cec-V1.0-java",
        "android.hardware.weaver-V1.0-java",
        "android.hardware.biometrics.face-V1.0-java",
        "android.hardware.biometrics.fingerprint-V2.1-java",
+209 −69
Original line number Diff line number Diff line
@@ -17,11 +17,18 @@
package com.android.server.hdmi;

import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.CecMessage;
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.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Handler;
import android.os.IHwBinder;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;

@@ -78,6 +85,11 @@ final class HdmiCecController {

    private static final int MAX_CEC_MESSAGE_HISTORY = 200;

    private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;

    /** Cookie for matching the right end point. */
    protected static final int HDMI_CEC_HAL_DEATH_COOKIE = 353;

    // Predicate for whether the given logical address is remote device's one or not.
    private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() {
        @Override
@@ -101,10 +113,6 @@ final class HdmiCecController {
    // device or issued by internal state change.
    private Handler mControlHandler;

    // Stores the pointer to the native implementation of the service that
    // interacts with HAL.
    private volatile long mNativePtr;

    private final HdmiControlService mService;

    // Stores the local CEC devices in the system. Device type is used for key.
@@ -142,21 +150,19 @@ final class HdmiCecController {
    static HdmiCecController createWithNativeWrapper(
            HdmiControlService service, NativeWrapper nativeWrapper) {
        HdmiCecController controller = new HdmiCecController(service, nativeWrapper);
            long nativePtr = nativeWrapper
                .nativeInit(controller, service.getServiceLooper().getQueue());
            if (nativePtr == 0L) {
                controller = null;
        String nativePtr = nativeWrapper.nativeInit();
        if (nativePtr == null) {
            HdmiLogger.warning("Couldn't get tv.cec service.");
            return null;
        }

            controller.init(nativePtr);
        controller.init(nativeWrapper);
        return controller;
    }

    private void init(long nativePtr) {
    private void init(NativeWrapper nativeWrapper) {
        mIoHandler = new Handler(mService.getIoLooper());
        mControlHandler = new Handler(mService.getServiceLooper());
        mNativePtr = nativePtr;
        nativeWrapper.setCallback(new HdmiCecCallback());
    }

    @ServiceThreadOnly
@@ -251,7 +257,7 @@ final class HdmiCecController {


    HdmiPortInfo[] getPortInfos() {
        return mNativeWrapperImpl.nativeGetPortInfos(mNativePtr);
        return mNativeWrapperImpl.nativeGetPortInfos();
    }

    /**
@@ -279,7 +285,7 @@ final class HdmiCecController {
    int addLogicalAddress(int newLogicalAddress) {
        assertRunOnServiceThread();
        if (HdmiUtils.isValidAddress(newLogicalAddress)) {
            return mNativeWrapperImpl.nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
            return mNativeWrapperImpl.nativeAddLogicalAddress(newLogicalAddress);
        } else {
            return Result.FAILURE_INVALID_ARGS;
        }
@@ -296,7 +302,7 @@ final class HdmiCecController {
        for (int i = 0; i < mLocalDevices.size(); ++i) {
            mLocalDevices.valueAt(i).clearAddress();
        }
        mNativeWrapperImpl.nativeClearLogicalAddress(mNativePtr);
        mNativeWrapperImpl.nativeClearLogicalAddress();
    }

    @ServiceThreadOnly
@@ -316,7 +322,7 @@ final class HdmiCecController {
    @ServiceThreadOnly
    int getPhysicalAddress() {
        assertRunOnServiceThread();
        return mNativeWrapperImpl.nativeGetPhysicalAddress(mNativePtr);
        return mNativeWrapperImpl.nativeGetPhysicalAddress();
    }

    /**
@@ -327,7 +333,7 @@ final class HdmiCecController {
    @ServiceThreadOnly
    int getVersion() {
        assertRunOnServiceThread();
        return mNativeWrapperImpl.nativeGetVersion(mNativePtr);
        return mNativeWrapperImpl.nativeGetVersion();
    }

    /**
@@ -338,7 +344,7 @@ final class HdmiCecController {
    @ServiceThreadOnly
    int getVendorId() {
        assertRunOnServiceThread();
        return mNativeWrapperImpl.nativeGetVendorId(mNativePtr);
        return mNativeWrapperImpl.nativeGetVendorId();
    }

    /**
@@ -351,7 +357,7 @@ final class HdmiCecController {
    void setOption(int flag, boolean enabled) {
        assertRunOnServiceThread();
        HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
        mNativeWrapperImpl.nativeSetOption(mNativePtr, flag, enabled);
        mNativeWrapperImpl.nativeSetOption(flag, enabled);
    }

    /**
@@ -365,7 +371,7 @@ final class HdmiCecController {
        if (!LanguageTag.isLanguage(language)) {
            return;
        }
        mNativeWrapperImpl.nativeSetLanguage(mNativePtr, language);
        mNativeWrapperImpl.nativeSetLanguage(language);
    }

    /**
@@ -377,7 +383,7 @@ final class HdmiCecController {
    @ServiceThreadOnly
    void enableAudioReturnChannel(int port, boolean enabled) {
        assertRunOnServiceThread();
        mNativeWrapperImpl.nativeEnableAudioReturnChannel(mNativePtr, port, enabled);
        mNativeWrapperImpl.nativeEnableAudioReturnChannel(port, enabled);
    }

    /**
@@ -389,7 +395,7 @@ final class HdmiCecController {
    @ServiceThreadOnly
    boolean isConnected(int port) {
        assertRunOnServiceThread();
        return mNativeWrapperImpl.nativeIsConnected(mNativePtr, port);
        return mNativeWrapperImpl.nativeIsConnected(port);
    }

    /**
@@ -511,7 +517,7 @@ final class HdmiCecController {
            // <Polling Message> is a message which has empty body.
            int ret =
                    mNativeWrapperImpl.nativeSendCecCommand(
                        mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY);
                        sourceAddress, destinationAddress, EMPTY_BODY);
            if (ret == SendMessageResult.SUCCESS) {
                return true;
            } else if (ret != SendMessageResult.NACK) {
@@ -615,7 +621,7 @@ final class HdmiCecController {
                int i = 0;
                int errorCode = SendMessageResult.SUCCESS;
                do {
                    errorCode = mNativeWrapperImpl.nativeSendCecCommand(mNativePtr,
                    errorCode = mNativeWrapperImpl.nativeSendCecCommand(
                        cecMessage.getSource(), cecMessage.getDestination(), body);
                    if (errorCode == SendMessageResult.SUCCESS) {
                        break;
@@ -639,7 +645,7 @@ final class HdmiCecController {
    }

    /**
     * Called by native when incoming CEC message arrived.
     * Called when incoming CEC message arrived.
     */
    @ServiceThreadOnly
    private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
@@ -651,7 +657,7 @@ final class HdmiCecController {
    }

    /**
     * Called by native when a hotplug event issues.
     * Called when a hotplug event issues.
     */
    @ServiceThreadOnly
    private void handleHotplug(int port, boolean connected) {
@@ -687,18 +693,19 @@ final class HdmiCecController {
    }

    protected interface NativeWrapper {
        long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
        int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body);
        int nativeAddLogicalAddress(long controllerPtr, int logicalAddress);
        void nativeClearLogicalAddress(long controllerPtr);
        int nativeGetPhysicalAddress(long controllerPtr);
        int nativeGetVersion(long controllerPtr);
        int nativeGetVendorId(long controllerPtr);
        HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
        void nativeSetOption(long controllerPtr, int flag, boolean enabled);
        void nativeSetLanguage(long controllerPtr, String language);
        void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag);
        boolean nativeIsConnected(long controllerPtr, int port);
        String nativeInit();
        void setCallback(HdmiCecCallback callback);
        int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body);
        int nativeAddLogicalAddress(int logicalAddress);
        void nativeClearLogicalAddress();
        int nativeGetPhysicalAddress();
        int nativeGetVersion();
        int nativeGetVendorId();
        HdmiPortInfo[] nativeGetPortInfos();
        void nativeSetOption(int flag, boolean enabled);
        void nativeSetLanguage(String language);
        void nativeEnableAudioReturnChannel(int port, boolean flag);
        boolean nativeIsConnected(int port);
    }

    private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue);
@@ -716,67 +723,200 @@ final class HdmiCecController {
        int port, boolean flag);
    private static native boolean nativeIsConnected(long controllerPtr, int port);

    private static final class NativeWrapperImpl implements NativeWrapper {
    private static final class NativeWrapperImpl implements NativeWrapper,
            IHwBinder.DeathRecipient, getPhysicalAddressCallback {
        private IHdmiCec mHdmiCec;
        private final Object mLock = new Object();
        private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;

        @Override
        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
            return HdmiCecController.nativeInit(handler, messageQueue);
        public String nativeInit() {
            return (connectToHal() ? mHdmiCec.toString() : null);
        }

        boolean connectToHal() {
            try {
                mHdmiCec = IHdmiCec.getService();
                try {
                    mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
                } catch (RemoteException e) {
                    HdmiLogger.error("Couldn't link to death : ", e);
                }
            } catch (RemoteException e) {
                HdmiLogger.error("Couldn't get tv.cec service : ", e);
                return false;
            }
            return true;
        }

        @Override
        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
            byte[] body) {
            return HdmiCecController.nativeSendCecCommand(controllerPtr, srcAddress, dstAddress, body);
        public void setCallback(HdmiCecCallback callback) {
            try {
                mHdmiCec.setCallback(callback);
            } catch (RemoteException e) {
                HdmiLogger.error("Couldn't initialise tv.cec callback : ", e);
            }
        }

        @Override
        public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
            return HdmiCecController.nativeAddLogicalAddress(controllerPtr, logicalAddress);
        public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) {
            CecMessage message = new CecMessage();
            message.initiator = srcAddress;
            message.destination = dstAddress;
            message.body = new ArrayList<>(body.length);
            for (byte b : body) {
                message.body.add(b);
            }
            try {
                return mHdmiCec.sendMessage(message);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to send CEC message : ", e);
                return SendMessageResult.FAIL;
            }
        }

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

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

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

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

        @Override
        public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
            return HdmiCecController.nativeGetPortInfos(controllerPtr);
        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 nativeSetOption(long controllerPtr, int flag, boolean enabled) {
            HdmiCecController.nativeSetOption(controllerPtr, flag, enabled);
        public HdmiPortInfo[] nativeGetPortInfos() {
            try {
                ArrayList<android.hardware.tv.cec.V1_0.HdmiPortInfo> hdmiPortInfos =
                        mHdmiCec.getPortInfo();
                HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()];
                int i = 0;
                for (android.hardware.tv.cec.V1_0.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 void nativeSetLanguage(long controllerPtr, String language) {
            HdmiCecController.nativeSetLanguage(controllerPtr, language);
        public void nativeSetOption(int flag, boolean enabled) {
            try {
                mHdmiCec.setOption(flag, enabled);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to set option : ", e);
            }
        }

        @Override
        public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
            HdmiCecController.nativeEnableAudioReturnChannel(controllerPtr, port, flag);
        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 boolean nativeIsConnected(int port) {
            try {
                return mHdmiCec.isConnected(port);
            } catch (RemoteException e) {
                HdmiLogger.error("Failed to get connection info : ", e);
                return false;
            }
        }

        @Override
        public void serviceDied(long cookie) {
            if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
                HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting");
                connectToHal();
            }
        }

        @Override
        public void onValues(int result, short addr) {
            if (result == Result.SUCCESS) {
                synchronized (mLock) {
                    mPhysicalAddress = new Short(addr).intValue();
                }
            }
        }
    }

    final class HdmiCecCallback extends IHdmiCecCallback.Stub {
        @Override
        public void onCecMessage(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);
            }
            runOnServiceThread(
                    () -> handleIncomingCecCommand(message.initiator, message.destination, body));
        }

        @Override
        public boolean nativeIsConnected(long controllerPtr, int port) {
            return HdmiCecController.nativeIsConnected(controllerPtr, port);
        public void onHotplugEvent(HotplugEvent event) throws RemoteException {
            runOnServiceThread(() -> handleHotplug(event.portId, event.connected));
        }
    }

+4 −0
Original line number Diff line number Diff line
@@ -71,6 +71,10 @@ final class HdmiLogger {
        getLogger().errorInternal(toLogString(logMessage, objs));
    }

    static final void error(String logMessage, Exception e, Object... objs) {
        getLogger().errorInternal(toLogString(logMessage + e, objs));
    }

    private void errorInternal(String logMessage) {
        String log = updateLog(mErrorTimingCache, logMessage);
        if (!log.isEmpty()) {
+16 −14
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.server.hdmi;

import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.MessageQueue;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.hdmi.HdmiCecController.NativeWrapper;
@@ -53,13 +52,16 @@ final class FakeNativeWrapper implements NativeWrapper {
    private HdmiPortInfo[] mHdmiPortInfo = null;

    @Override
    public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
        return 1L;
    public String nativeInit() {
        return "[class or subclass of IHdmiCec]@Proxy";
    }

    @Override
    public void setCallback(HdmiCecController.HdmiCecCallback callback) {}

    @Override
    public int nativeSendCecCommand(
            long controllerPtr, int srcAddress, int dstAddress, byte[] body) {
            int srcAddress, int dstAddress, byte[] body) {
        if (body.length == 0) {
            return mPollAddressResponse[dstAddress];
        } else {
@@ -69,30 +71,30 @@ final class FakeNativeWrapper implements NativeWrapper {
    }

    @Override
    public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
    public int nativeAddLogicalAddress(int logicalAddress) {
        return 0;
    }

    @Override
    public void nativeClearLogicalAddress(long controllerPtr) {}
    public void nativeClearLogicalAddress() {}

    @Override
    public int nativeGetPhysicalAddress(long controllerPtr) {
    public int nativeGetPhysicalAddress() {
        return mMyPhysicalAddress;
    }

    @Override
    public int nativeGetVersion(long controllerPtr) {
    public int nativeGetVersion() {
        return 0;
    }

    @Override
    public int nativeGetVendorId(long controllerPtr) {
    public int nativeGetVendorId() {
        return 0;
    }

    @Override
    public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
    public HdmiPortInfo[] nativeGetPortInfos() {
        if (mHdmiPortInfo == null) {
            mHdmiPortInfo = new HdmiPortInfo[1];
            mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true);
@@ -101,16 +103,16 @@ final class FakeNativeWrapper implements NativeWrapper {
    }

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

    @Override
    public void nativeSetLanguage(long controllerPtr, String language) {}
    public void nativeSetLanguage(String language) {}

    @Override
    public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {}
    public void nativeEnableAudioReturnChannel(int port, boolean flag) {}

    @Override
    public boolean nativeIsConnected(long controllerPtr, int port) {
    public boolean nativeIsConnected(int port) {
        return false;
    }