Introduce @ServiceThreadOnly and @IothreadOnly to HdmiControlService

Many of hdmi service modules assumes that it runs on
service thread without any lock. But it's a bit
hard to distinguish whether a method runs on
service thread or not even though there is run-time
assertion (runOnServiceThread()) is top of method.
@ServiceThreadOnly interface documents that a method should
run on service thread while @IoThreadOnly documents
that a method should run on io thread.

Change-Id: Ia4a6a48675d2302fb2cb7a8a807fcf112da5d4e7
This commit is contained in:
Jungshik Jang
2014-06-23 18:03:10 +09:00
parent d4c1154353
commit a5b7414970
6 changed files with 164 additions and 11 deletions

View File

@@ -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 {
}
}

View File

@@ -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 {
*
* <p>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 {
*
* <p>Declared as package-private. accessed by {@link HdmiControlService} only.
*/
@ServiceThreadOnly
int getVersion() {
assertRunOnServiceThread();
return nativeGetVersion(mNativePtr);
@@ -297,6 +307,7 @@ final class HdmiCecController {
*
* <p>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 {
*
* <p>Declared as package-private. accessed by {@link HdmiControlService} only.
*/
@ServiceThreadOnly
List<HdmiCecLocalDevice> 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<Integer> 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));

View File

@@ -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 <Get Menu Language>:" + 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
<T extends FeatureAction> boolean hasAction(final Class<T> clazz) {
assertRunOnServiceThread();
for (FeatureAction action : mActions) {
@@ -293,6 +307,7 @@ abstract class HdmiCecLocalDevice {
}
// Returns all actions matched with given class type.
@ServiceThreadOnly
<T extends FeatureAction> List<T> getActions(final Class<T> clazz) {
assertRunOnServiceThread();
ArrayList<T> 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
<T extends FeatureAction> void removeAction(final Class<T> clazz) {
assertRunOnServiceThread();
removeActionExcept(clazz, null);
}
// Remove all actions matched with the given Class type besides |exception|.
@ServiceThreadOnly
<T extends FeatureAction> void removeActionExcept(final Class<T> 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);

View File

@@ -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();
}

View File

@@ -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<SendKeyAction> 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<VendorSpecificAction> 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 <Initiate Arc> is started by <Request ARC Initiation>
@@ -341,6 +354,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
@Override
@ServiceThreadOnly
protected boolean handleTerminateArc(HdmiCecMessage message) {
assertRunOnServiceThread();
// In case where <Terminate Arc> is started by <Request ARC Termination>
@@ -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 {
* <p>Declared as package-private. accessed by {@link HdmiControlService} only.
* This is not thread-safe. For thread safety, call {@link #getSafeDeviceInfoList(boolean)}.
*/
@ServiceThreadOnly
List<HdmiCecDeviceInfo> getDeviceInfoList(boolean includelLocalDevice) {
assertRunOnServiceThread();
if (includelLocalDevice) {
@@ -463,6 +482,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
}
@ServiceThreadOnly
private void updateSafeDeviceInfoList() {
assertRunOnServiceThread();
List<HdmiCecDeviceInfo> 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.

View File

@@ -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<Integer> deviceTypes) {
assertRunOnServiceThread();
// A container for [Logical Address, Local device info].
final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>();
final SparseIntArray finished = new SparseIntArray();
@@ -195,7 +198,9 @@ public final class HdmiControlService extends SystemService {
}
}
@ServiceThreadOnly
private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> 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<HdmiPortInfo> 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();