diff --git a/services/core/java/com/android/server/hdmi/HdmiAnnotations.java b/services/core/java/com/android/server/hdmi/HdmiAnnotations.java new file mode 100644 index 0000000000000..969595d812dc6 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiAnnotations.java @@ -0,0 +1,47 @@ +/* + * 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 java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation container for Hdmi control service package. + */ +public class HdmiAnnotations { + /** + * Annotation type to used to mark a method which should be run on service thread. + * This annotation should go with {@code assertRunOnServiceThread} used to verify + * whether it's called from service thread. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface ServiceThreadOnly { + } + + /** + * Annotation type to used to mark a method which should be run on io thread. + * This annotation should go with {@code assertRunOnIoThread} used to verify + * whether it's called from io thread. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface IoThreadOnly { + } +} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 6d05e82cad5d8..4fbe84515ecdf 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -26,6 +26,8 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.util.Predicate; +import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly; +import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; import libcore.util.EmptyArray; @@ -144,7 +146,9 @@ final class HdmiCecController { mNativePtr = nativePtr; } + @ServiceThreadOnly void addLocalDevice(int deviceType, HdmiCecLocalDevice device) { + assertRunOnServiceThread(); mLocalDevices.put(deviceType, device); } @@ -161,6 +165,7 @@ final class HdmiCecController { * Otherwise, scan address will start from {@code preferredAddress} * @param callback callback interface to report allocated logical address to caller */ + @ServiceThreadOnly void allocateLogicalAddress(final int deviceType, final int preferredAddress, final AllocateAddressCallback callback) { assertRunOnServiceThread(); @@ -173,6 +178,7 @@ final class HdmiCecController { }); } + @IoThreadOnly private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress, final AllocateAddressCallback callback) { assertRunOnIoThread(); @@ -245,6 +251,7 @@ final class HdmiCecController { * @param newLogicalAddress a logical address to be added * @return 0 on success. Otherwise, returns negative value */ + @ServiceThreadOnly int addLogicalAddress(int newLogicalAddress) { assertRunOnServiceThread(); if (HdmiCec.isValidAddress(newLogicalAddress)) { @@ -259,6 +266,7 @@ final class HdmiCecController { * *

Declared as package-private. accessed by {@link HdmiControlService} only. */ + @ServiceThreadOnly void clearLogicalAddress() { assertRunOnServiceThread(); // TODO: consider to backup logical address so that new logical address @@ -277,6 +285,7 @@ final class HdmiCecController { * @return CEC physical address of the device. The range of success address * is between 0x0000 and 0xFFFF. If failed it returns -1 */ + @ServiceThreadOnly int getPhysicalAddress() { assertRunOnServiceThread(); return nativeGetPhysicalAddress(mNativePtr); @@ -287,6 +296,7 @@ final class HdmiCecController { * *

Declared as package-private. accessed by {@link HdmiControlService} only. */ + @ServiceThreadOnly int getVersion() { assertRunOnServiceThread(); return nativeGetVersion(mNativePtr); @@ -297,6 +307,7 @@ final class HdmiCecController { * *

Declared as package-private. accessed by {@link HdmiControlService} only. */ + @ServiceThreadOnly int getVendorId() { assertRunOnServiceThread(); return nativeGetVendorId(mNativePtr); @@ -311,6 +322,7 @@ final class HdmiCecController { * @param value a value of option. Actual value varies flag. For more * details, look at description of flags */ + @ServiceThreadOnly void setOption(int flag, int value) { assertRunOnServiceThread(); nativeSetOption(mNativePtr, flag, value); @@ -321,6 +333,7 @@ final class HdmiCecController { * * @param enabled whether to enable/disable ARC */ + @ServiceThreadOnly void setAudioReturnChannel(boolean enabled) { assertRunOnServiceThread(); nativeSetAudioReturnChannel(mNativePtr, enabled); @@ -332,6 +345,7 @@ final class HdmiCecController { * @param port port number to check connection status * @return true if connected; otherwise, return false */ + @ServiceThreadOnly boolean isConnected(int port) { assertRunOnServiceThread(); return nativeIsConnected(mNativePtr, port); @@ -347,6 +361,7 @@ final class HdmiCecController { * @param pickStrategy strategy how to pick polling candidates * @param retryCount the number of retry used to send polling message to remote devices */ + @ServiceThreadOnly void pollDevices(DevicePollingCallback callback, int pickStrategy, int retryCount) { assertRunOnServiceThread(); @@ -360,6 +375,7 @@ final class HdmiCecController { * *

Declared as package-private. accessed by {@link HdmiControlService} only. */ + @ServiceThreadOnly List getLocalDeviceList() { assertRunOnServiceThread(); return HdmiUtils.sparseArrayToList(mLocalDevices); @@ -400,7 +416,9 @@ final class HdmiCecController { return pollingCandidates; } + @ServiceThreadOnly private boolean isAllocatedLocalDeviceAddress(int address) { + assertRunOnServiceThread(); for (int i = 0; i < mLocalDevices.size(); ++i) { if (mLocalDevices.valueAt(i).isAddressOf(address)) { return true; @@ -409,6 +427,7 @@ final class HdmiCecController { return false; } + @ServiceThreadOnly private void runDevicePolling(final List candidates, final int retryCount, final DevicePollingCallback callback) { assertRunOnServiceThread(); @@ -433,6 +452,7 @@ final class HdmiCecController { }); } + @IoThreadOnly private boolean sendPollMessage(int address, int retryCount) { assertRunOnIoThread(); for (int i = 0; i < retryCount; ++i) { @@ -480,6 +500,7 @@ final class HdmiCecController { return isAllocatedLocalDeviceAddress(address); } + @ServiceThreadOnly private void onReceiveCommand(HdmiCecMessage message) { assertRunOnServiceThread(); if (isAcceptableAddress(message.getDestination()) @@ -493,16 +514,20 @@ final class HdmiCecController { HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand( sourceAddress, message.getSource(), message.getOpcode(), HdmiConstants.ABORT_REFUSED); - sendCommand(cecMessage, null); + sendCommand(cecMessage); } } + @ServiceThreadOnly void sendCommand(HdmiCecMessage cecMessage) { + assertRunOnServiceThread(); sendCommand(cecMessage, null); } + @ServiceThreadOnly void sendCommand(final HdmiCecMessage cecMessage, final HdmiControlService.SendMessageCallback callback) { + assertRunOnServiceThread(); runOnIoThread(new Runnable() { @Override public void run() { @@ -527,6 +552,7 @@ final class HdmiCecController { /** * Called by native when incoming CEC message arrived. */ + @ServiceThreadOnly private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { assertRunOnServiceThread(); onReceiveCommand(HdmiCecMessageBuilder.of(srcAddress, dstAddress, body)); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index f86d655af4707..6f7f5c2dca5c9 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -23,6 +23,7 @@ import android.os.Looper; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import java.util.ArrayList; import java.util.Iterator; @@ -87,7 +88,9 @@ abstract class HdmiCecLocalDevice { } } + @ServiceThreadOnly void init() { + assertRunOnServiceThread(); mPreferredAddress = HdmiCec.ADDR_UNREGISTERED; // TODO: load preferred address from permanent storage. } @@ -103,9 +106,9 @@ abstract class HdmiCecLocalDevice { * @param message incoming message * @return true if consumed a message; otherwise, return false. */ + @ServiceThreadOnly final boolean dispatchMessage(HdmiCecMessage message) { assertRunOnServiceThread(); - int dest = message.getDestination(); if (dest != mAddress && dest != HdmiCec.ADDR_BROADCAST) { return false; @@ -115,9 +118,9 @@ abstract class HdmiCecLocalDevice { return onMessage(message); } + @ServiceThreadOnly protected final boolean onMessage(HdmiCecMessage message) { assertRunOnServiceThread(); - if (dispatchMessageToAction(message)) { return true; } @@ -147,7 +150,9 @@ abstract class HdmiCecLocalDevice { } } + @ServiceThreadOnly private boolean dispatchMessageToAction(HdmiCecMessage message) { + assertRunOnServiceThread(); for (FeatureAction action : mActions) { if (action.processCommand(message)) { return true; @@ -156,6 +161,7 @@ abstract class HdmiCecLocalDevice { return false; } + @ServiceThreadOnly protected boolean handleGivePhysicalAddress() { assertRunOnServiceThread(); @@ -166,9 +172,9 @@ abstract class HdmiCecLocalDevice { return true; } + @ServiceThreadOnly protected boolean handleGiveDeviceVendorId() { assertRunOnServiceThread(); - int vendorId = mService.getVendorId(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( mAddress, vendorId); @@ -176,9 +182,9 @@ abstract class HdmiCecLocalDevice { return true; } + @ServiceThreadOnly protected boolean handleGetCecVersion(HdmiCecMessage message) { assertRunOnServiceThread(); - int version = mService.getCecVersion(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(), message.getSource(), version); @@ -186,9 +192,9 @@ abstract class HdmiCecLocalDevice { return true; } + @ServiceThreadOnly protected boolean handleGetMenuLanguage(HdmiCecMessage message) { assertRunOnServiceThread(); - Slog.w(TAG, "Only TV can handle :" + message.toString()); mService.sendCecCommand( HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress, @@ -197,9 +203,9 @@ abstract class HdmiCecLocalDevice { return true; } + @ServiceThreadOnly protected boolean handleGiveOsdName(HdmiCecMessage message) { assertRunOnServiceThread(); - // Note that since this method is called after logical address allocation is done, // mDeviceInfo should not be null. HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand( @@ -236,45 +242,52 @@ abstract class HdmiCecLocalDevice { return false; } + @ServiceThreadOnly final void handleAddressAllocated(int logicalAddress) { assertRunOnServiceThread(); - mAddress = mPreferredAddress = logicalAddress; onAddressAllocated(logicalAddress); } + @ServiceThreadOnly HdmiCecDeviceInfo getDeviceInfo() { assertRunOnServiceThread(); return mDeviceInfo; } + @ServiceThreadOnly void setDeviceInfo(HdmiCecDeviceInfo info) { assertRunOnServiceThread(); mDeviceInfo = info; } // Returns true if the logical address is same as the argument. + @ServiceThreadOnly boolean isAddressOf(int addr) { assertRunOnServiceThread(); return addr == mAddress; } // Resets the logical address to unregistered(15), meaning the logical device is invalid. + @ServiceThreadOnly void clearAddress() { assertRunOnServiceThread(); mAddress = HdmiCec.ADDR_UNREGISTERED; } + @ServiceThreadOnly void setPreferredAddress(int addr) { assertRunOnServiceThread(); mPreferredAddress = addr; } + @ServiceThreadOnly int getPreferredAddress() { assertRunOnServiceThread(); return mPreferredAddress; } + @ServiceThreadOnly void addAndStartAction(final FeatureAction action) { assertRunOnServiceThread(); mActions.add(action); @@ -282,6 +295,7 @@ abstract class HdmiCecLocalDevice { } // See if we have an action of a given type in progress. + @ServiceThreadOnly boolean hasAction(final Class clazz) { assertRunOnServiceThread(); for (FeatureAction action : mActions) { @@ -293,6 +307,7 @@ abstract class HdmiCecLocalDevice { } // Returns all actions matched with given class type. + @ServiceThreadOnly List getActions(final Class clazz) { assertRunOnServiceThread(); ArrayList actions = new ArrayList<>(); @@ -309,17 +324,21 @@ abstract class HdmiCecLocalDevice { * * @param action {@link FeatureAction} to remove */ + @ServiceThreadOnly void removeAction(final FeatureAction action) { assertRunOnServiceThread(); mActions.remove(action); } // Remove all actions matched with the given Class type. + @ServiceThreadOnly void removeAction(final Class clazz) { + assertRunOnServiceThread(); removeActionExcept(clazz, null); } // Remove all actions matched with the given Class type besides |exception|. + @ServiceThreadOnly void removeActionExcept(final Class clazz, final FeatureAction exception) { assertRunOnServiceThread(); @@ -352,7 +371,9 @@ abstract class HdmiCecLocalDevice { return mService; } + @ServiceThreadOnly final boolean isConnectedToArcPort(int path) { + assertRunOnServiceThread(); return mService.isConnectedToArcPort(path); } @@ -442,11 +463,13 @@ abstract class HdmiCecLocalDevice { } } + @ServiceThreadOnly HdmiCecMessageCache getCecMessageCache() { assertRunOnServiceThread(); return mCecMessageCache; } + @ServiceThreadOnly int pathToPortId(int newPath) { assertRunOnServiceThread(); return mService.pathToPortId(newPath); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 01345ef0db975..d7e36b37d00bd 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -21,6 +21,8 @@ import android.hardware.hdmi.IHdmiControlCallback; import android.os.RemoteException; import android.util.Slog; +import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; + /** * Represent a logical device of type Playback residing in Android system. */ @@ -32,11 +34,14 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected void onAddressAllocated(int logicalAddress) { + assertRunOnServiceThread(); mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( mAddress, mService.getPhysicalAddress(), mDeviceType)); } + @ServiceThreadOnly void oneTouchPlay(IHdmiControlCallback callback) { assertRunOnServiceThread(); if (hasAction(OneTouchPlayAction.class)) { @@ -56,6 +61,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { addAndStartAction(action); } + @ServiceThreadOnly void queryDisplayStatus(IHdmiControlCallback callback) { assertRunOnServiceThread(); if (hasAction(DevicePowerStatusAction.class)) { @@ -73,7 +79,9 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { addAndStartAction(action); } + @ServiceThreadOnly private void invokeCallback(IHdmiControlCallback callback, int result) { + assertRunOnServiceThread(); try { callback.onComplete(result); } catch (RemoteException e) { @@ -82,7 +90,9 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly void onHotplug(int portId, boolean connected) { + assertRunOnServiceThread(); // TODO: clear devices connected to the given port id. mCecMessageCache.flushAll(); } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 1a3fcfe0572e3..1d5a7d3eb7baf 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -26,6 +26,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; +import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import java.util.ArrayList; import java.util.Collections; @@ -66,6 +67,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected void onAddressAllocated(int logicalAddress) { assertRunOnServiceThread(); // TODO: vendor-specific initialization here. @@ -76,7 +78,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mAddress, mService.getVendorId())); launchDeviceDiscovery(); - // TODO: Start routing control action, device discovery action. + // TODO: Start routing control action } /** @@ -85,6 +87,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param targetAddress logical address of the device to select * @param callback callback object to report the result with */ + @ServiceThreadOnly void deviceSelect(int targetAddress, IHdmiControlCallback callback) { assertRunOnServiceThread(); HdmiCecDeviceInfo targetDevice = getDeviceInfo(targetAddress); @@ -102,6 +105,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param portId new HDMI port to route to * @param callback callback object to report the result with */ + @ServiceThreadOnly void portSelect(int portId, IHdmiControlCallback callback) { assertRunOnServiceThread(); if (isInPresetInstallationMode()) { @@ -136,6 +140,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param keyCode key code to send. Defined in {@link android.view.KeyEvent}. * @param isPressed true if this is keypress event */ + @ServiceThreadOnly void sendKeyEvent(int keyCode, boolean isPressed) { assertRunOnServiceThread(); List action = getActions(SendKeyAction.class); @@ -162,6 +167,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected boolean handleGetMenuLanguage(HdmiCecMessage message) { assertRunOnServiceThread(); HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( @@ -176,6 +182,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { assertRunOnServiceThread(); // Ignore if [Device Discovery Action] is going on. @@ -198,6 +205,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected boolean handleVendorSpecificCommand(HdmiCecMessage message) { assertRunOnServiceThread(); List actions = Collections.emptyList(); @@ -223,6 +231,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return true; } + @ServiceThreadOnly private void launchDeviceDiscovery() { assertRunOnServiceThread(); clearDeviceInfoList(); @@ -257,12 +266,14 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } // Clear all device info. + @ServiceThreadOnly private void clearDeviceInfoList() { assertRunOnServiceThread(); mDeviceInfos.clear(); updateSafeDeviceInfoList(); } + @ServiceThreadOnly void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) { assertRunOnServiceThread(); HdmiCecDeviceInfo avr = getAvrDeviceInfo(); @@ -324,11 +335,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } + @ServiceThreadOnly void setAudioStatus(boolean mute, int volume) { mService.setAudioStatus(mute, volume); } @Override + @ServiceThreadOnly protected boolean handleInitiateArc(HdmiCecMessage message) { assertRunOnServiceThread(); // In case where is started by @@ -341,6 +354,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected boolean handleTerminateArc(HdmiCecMessage message) { assertRunOnServiceThread(); // In case where is started by @@ -355,6 +369,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { assertRunOnServiceThread(); if (!isMessageForSystemAudio(message)) { @@ -367,6 +382,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { assertRunOnServiceThread(); if (!isMessageForSystemAudio(message)) { @@ -396,6 +412,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @return {@code null} if it is new device. Otherwise, returns old {@HdmiCecDeviceInfo} * that has the same logical address as new one has. */ + @ServiceThreadOnly HdmiCecDeviceInfo addDeviceInfo(HdmiCecDeviceInfo deviceInfo) { assertRunOnServiceThread(); HdmiCecDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress()); @@ -416,6 +433,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param logicalAddress logical address of device to be removed * @return removed {@link HdmiCecDeviceInfo} it exists. Otherwise, returns {@code null} */ + @ServiceThreadOnly HdmiCecDeviceInfo removeDeviceInfo(int logicalAddress) { assertRunOnServiceThread(); HdmiCecDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress); @@ -432,6 +450,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { *

Declared as package-private. accessed by {@link HdmiControlService} only. * This is not thread-safe. For thread safety, call {@link #getSafeDeviceInfoList(boolean)}. */ + @ServiceThreadOnly List getDeviceInfoList(boolean includelLocalDevice) { assertRunOnServiceThread(); if (includelLocalDevice) { @@ -463,6 +482,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } + @ServiceThreadOnly private void updateSafeDeviceInfoList() { assertRunOnServiceThread(); List copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos); @@ -473,6 +493,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } + @ServiceThreadOnly private boolean isLocalDeviceAddress(int address) { assertRunOnServiceThread(); for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { @@ -493,11 +514,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @return {@link HdmiCecDeviceInfo} matched with the given {@code logicalAddress}. * Returns null if no logical address matched */ + @ServiceThreadOnly HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { assertRunOnServiceThread(); return mDeviceInfos.get(logicalAddress); } + @ServiceThreadOnly HdmiCecDeviceInfo getAvrDeviceInfo() { assertRunOnServiceThread(); return getDeviceInfo(HdmiCec.ADDR_AUDIO_SYSTEM); @@ -525,6 +548,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * * @param info device info of a new device. */ + @ServiceThreadOnly final void addCecDevice(HdmiCecDeviceInfo info) { assertRunOnServiceThread(); addDeviceInfo(info); @@ -540,6 +564,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * * @param address a logical address of a device to be removed */ + @ServiceThreadOnly final void removeCecDevice(int address) { assertRunOnServiceThread(); HdmiCecDeviceInfo info = removeDeviceInfo(address); @@ -555,6 +580,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param path routing path or physical address * @return {@link HdmiCecDeviceInfo} if the matched info is found; otherwise null */ + @ServiceThreadOnly final HdmiCecDeviceInfo getDeviceInfoByPath(int path) { assertRunOnServiceThread(); for (HdmiCecDeviceInfo info : getDeviceInfoList(false)) { @@ -574,6 +600,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { * @param logicalAddress logical address of a device to be searched * @return true if exist; otherwise false */ + @ServiceThreadOnly boolean isInDeviceList(int physicalAddress, int logicalAddress) { assertRunOnServiceThread(); HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress); @@ -584,6 +611,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } @Override + @ServiceThreadOnly void onHotplug(int portNo, boolean connected) { assertRunOnServiceThread(); // TODO: delegate onHotplug event to each local device. diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 77748786f4836..055751b51f17d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -40,6 +40,7 @@ import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.server.SystemService; +import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; import java.util.ArrayList; @@ -163,7 +164,9 @@ public final class HdmiControlService extends SystemService { // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. } + @ServiceThreadOnly private void initializeLocalDevices(final List deviceTypes) { + assertRunOnServiceThread(); // A container for [Logical Address, Local device info]. final SparseArray devices = new SparseArray<>(); final SparseIntArray finished = new SparseIntArray(); @@ -195,7 +198,9 @@ public final class HdmiControlService extends SystemService { } } + @ServiceThreadOnly private void notifyAddressAllocated(SparseArray devices) { + assertRunOnServiceThread(); for (int i = 0; i < devices.size(); ++i) { int address = devices.keyAt(i); HdmiCecLocalDevice device = devices.valueAt(i); @@ -205,7 +210,9 @@ public final class HdmiControlService extends SystemService { // Initialize HDMI port information. Combine the information from CEC and MHL HAL and // keep them in one place. + @ServiceThreadOnly private List initPortInfo() { + assertRunOnServiceThread(); HdmiPortInfo[] cecPortInfo = null; // CEC HAL provides majority of the info while MHL does only MHL support flag for @@ -325,6 +332,7 @@ public final class HdmiControlService extends SystemService { return mCecController.getVendorId(); } + @ServiceThreadOnly HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { assertRunOnServiceThread(); HdmiCecLocalDeviceTv tv = tv(); @@ -374,15 +382,21 @@ public final class HdmiControlService extends SystemService { * @param command CEC command to send out * @param callback interface used to the result of send command */ + @ServiceThreadOnly void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { + assertRunOnServiceThread(); mCecController.sendCommand(command, callback); } + @ServiceThreadOnly void sendCecCommand(HdmiCecMessage command) { + assertRunOnServiceThread(); mCecController.sendCommand(command, null); } + @ServiceThreadOnly boolean handleCecCommand(HdmiCecMessage message) { + assertRunOnServiceThread(); return dispatchMessageToLocalDevice(message); } @@ -390,7 +404,9 @@ public final class HdmiControlService extends SystemService { mCecController.setAudioReturnChannel(enabled); } + @ServiceThreadOnly private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { + assertRunOnServiceThread(); for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { if (device.dispatchMessage(message) && message.getDestination() != HdmiCec.ADDR_BROADCAST) { @@ -408,13 +424,12 @@ public final class HdmiControlService extends SystemService { * @param portNo hdmi port number where hot plug event issued. * @param connected whether to be plugged in or not */ + @ServiceThreadOnly void onHotplug(int portNo, boolean connected) { assertRunOnServiceThread(); - for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { device.onHotplug(portNo, connected); } - announceHotplugEvent(portNo, connected); } @@ -427,7 +442,9 @@ public final class HdmiControlService extends SystemService { * @param retryCount the number of retry used to send polling message to remote devices * @throw IllegalArgumentException if {@code pickStrategy} is invalid value */ + @ServiceThreadOnly void pollDevices(DevicePollingCallback callback, int pickStrategy, int retryCount) { + assertRunOnServiceThread(); mCecController.pollDevices(callback, checkPollStrategy(pickStrategy), retryCount); } @@ -700,6 +717,7 @@ public final class HdmiControlService extends SystemService { } } + @ServiceThreadOnly private void oneTouchPlay(final IHdmiControlCallback callback) { assertRunOnServiceThread(); HdmiCecLocalDevicePlayback source = playback(); @@ -711,6 +729,7 @@ public final class HdmiControlService extends SystemService { source.oneTouchPlay(callback); } + @ServiceThreadOnly private void queryDisplayStatus(final IHdmiControlCallback callback) { assertRunOnServiceThread(); HdmiCecLocalDevicePlayback source = playback();