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

Commit 2ae1019c authored by Jungshik Jang's avatar Jungshik Jang Committed by Android (Google) Code Review
Browse files

Merge "Implement cec message cache."

parents 8c90ff3b e81e108c
Loading
Loading
Loading
Loading
+25 −3
Original line number Diff line number Diff line
@@ -95,10 +95,10 @@ final class DeviceDiscoveryAction extends FeatureAction {
    private int mProcessedDeviceCount = 0;

    /**
     * @Constructor
     * Constructor.
     *
     * @param service
     * @param sourceAddress
     * @param service an instance of {@link HdmiControlService}.
     * @param sourceAddress a logical address which initiates this action
     */
    DeviceDiscoveryAction(HdmiControlService service, int sourceAddress,
            DeviceDiscoveryCallback callback) {
@@ -154,6 +154,11 @@ final class DeviceDiscoveryAction extends FeatureAction {
        }

        mActionTimer.clearTimerMessage();

        // Check cache first and send request if not exist.
        if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS)) {
            return;
        }
        sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(mSourceAddress, address));
        addTimer(mState, TIMEOUT_MS);
    }
@@ -173,6 +178,10 @@ final class DeviceDiscoveryAction extends FeatureAction {
        }

        mActionTimer.clearTimerMessage();

        if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_SET_OSD_NAME)) {
            return;
        }
        sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress, address));
        addTimer(mState, TIMEOUT_MS);
    }
@@ -193,10 +202,23 @@ final class DeviceDiscoveryAction extends FeatureAction {
        }

        mActionTimer.clearTimerMessage();

        if (mayProcessMessageIfCached(address, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) {
            return;
        }
        sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress, address));
        addTimer(mState, TIMEOUT_MS);
    }

    private boolean mayProcessMessageIfCached(int address, int opcode) {
        HdmiCecMessage message = mService.getCecMessageCache().getMessage(address, opcode);
        if (message != null) {
            processCommand(message);
            return true;
        }
        return false;
    }

    @Override
    boolean processCommand(HdmiCecMessage cmd) {
        switch (mState) {
+104 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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.hdmi.HdmiCec;
import android.hardware.hdmi.HdmiCecMessage;
import android.util.FastImmutableArraySet;
import android.util.SparseArray;

/**
 * Cache for incoming message. It caches {@link HdmiCecMessage} with source address and opcode
 * as a key.
 *
 * <p>Note that whenever a device is removed it should call {@link #flushMessagesFrom(int)}
 * to clean up messages come from the device.
 */
final class HdmiCecMessageCache {
    private static final FastImmutableArraySet<Integer> CACHEABLE_OPCODES = new FastImmutableArraySet<>(
            new Integer[] {
                    HdmiCec.MESSAGE_SET_OSD_NAME,
                    HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS,
                    HdmiCec.MESSAGE_DEVICE_VENDOR_ID,
                    HdmiCec.MESSAGE_CEC_VERSION,
            });

    // It's like [Source Logical Address, [Opcode, HdmiCecMessage]].
    private final SparseArray<SparseArray<HdmiCecMessage>> mCache = new SparseArray<>();

    HdmiCecMessageCache() {
    }

    /**
     * Return a {@link HdmiCecMessage} corresponding to the given {@code address} and
     * {@code opcode}.
     *
     * @param address a logical address of source device
     * @param opcode opcode of message
     * @return null if has no {@link HdmiCecMessage} matched to the given {@code address} and {code
     *         opcode}
     */
    public HdmiCecMessage getMessage(int address, int opcode) {
        SparseArray<HdmiCecMessage> messages = mCache.get(address);
        if (messages == null) {
            return null;
        }

        return messages.get(opcode);
    }

    /**
     * Flush all {@link HdmiCecMessage}s sent from the given {@code address}.
     *
     * @param address a logical address of source device
     */
    public void flushMessagesFrom(int address) {
        mCache.remove(address);
    }

    /**
     * Flush all cached {@link HdmiCecMessage}s.
     */
    public void flushAll() {
        mCache.clear();
    }

    /**
     * Cache incoming {@link HdmiCecMessage}. If opcode of message is not listed on
     * cacheable opcodes list, just ignore it.
     *
     * @param message a {@link HdmiCecMessage} to be cached
     */
    public void cacheMessage(HdmiCecMessage message) {
        int opcode = message.getOpcode();
        if (!isCacheable(opcode)) {
            return;
        }

        int source = message.getSource();
        SparseArray<HdmiCecMessage> messages = mCache.get(source);
        if (messages == null) {
            messages = new SparseArray<>();
            mCache.put(source, messages);
        }
        messages.put(opcode, message);
    }

    private boolean isCacheable(int opcode) {
        return CACHEABLE_OPCODES.contains(opcode);
    }
}
+20 −1
Original line number Diff line number Diff line
@@ -117,6 +117,8 @@ public final class HdmiControlService extends SystemService {
    private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
            new ArrayList<>();

    private final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache();

    @Nullable
    private HdmiCecController mCecController;

@@ -368,6 +370,9 @@ public final class HdmiControlService extends SystemService {
    }

    boolean handleCecCommand(HdmiCecMessage message) {
        // Cache incoming message. Note that it caches only white-listed one.
        mCecMessageCache.cacheMessage(message);

        // Commands that queries system information replies directly instead
        // of creating FeatureAction because they are state-less.
        switch (message.getOpcode()) {
@@ -441,7 +446,6 @@ public final class HdmiControlService extends SystemService {
        return strategy | iterationStrategy;
    }


    /**
     * Launch device discovery sequence. It starts with clearing the existing device info list.
     * Note that it assumes that logical address of all local devices is already allocated.
@@ -451,6 +455,7 @@ public final class HdmiControlService extends SystemService {
    void launchDeviceDiscovery(final int sourceAddress) {
        // At first, clear all existing device infos.
        mCecController.clearDeviceInfoList();
        mCecMessageCache.flushAll();

        // TODO: check whether TV is one of local devices.
        DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, sourceAddress,
@@ -785,4 +790,18 @@ public final class HdmiControlService extends SystemService {
        // TODO: Implement this.
        return false;
    }

    /**
     * Called when a device is removed or removal of device is detected.
     *
     * @param address a logical address of a device to be removed
     */
    void removeCecDevice(int address) {
        mCecController.removeDeviceInfo(address);
        mCecMessageCache.flushMessagesFrom(address);
    }

    HdmiCecMessageCache getCecMessageCache() {
        return mCecMessageCache;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ final class HotplugDetectionAction extends FeatureAction {
    }

    private void removeDevice(int removedAddress) {
        mService.removeCecDevice(removedAddress);
        // TODO: implements following steps.
        // 1. Launch routing control sequence
        // 2. Stop one touch play sequence if removed device is the device to be selected.