hdmi插入,信号源app hdmi连接logo显示
hdmi拔掉,信号源app hdmi连接logo不显示
代码流程分析。
一,
hdmi在插入时,5v检测会探测到是哪个hdmi插入的。
我猜测tv_input.amlogic.so会一直read这个状态。
tv_input( 4331): TvCallback::onTvEvent source = 7, status = 0
hdmi拔掉的时候,amlogic不开源的tv_input.amlogic.so向上层callback一个消息。source=7 代表是hdmi3,status = 0代表拔掉。
vendor/amlogic/apps/TvLibRelease/tv_input/tv_input.cpp
static int notify_HDMI_device_available(tv_input_private_t *priv, tv_source_input_t source_input, uint32_t port_id, int type)
{
tv_input_event_t event;
event.device_info.device_id = source_input;
event.device_info.type = TV_INPUT_TYPE_HDMI;
event.type = type;
event.device_info.hdmi.port_id = port_id;
event.device_info.audio_type = AUDIO_DEVICE_NONE;
event.device_info.audio_address = NULL;
priv->callback->notify(&priv->device, &event, priv->callback_data);
return 0;
}
二,frameworks/base/services/core/jni/com_android_server_tv_TvInputHal.cpp
void JTvInputHal::notify(
tv_input_device_t* dev, tv_input_event_t* event, void* data) {
JTvInputHal* thiz = (JTvInputHal*)data;
ALOGE("JTvInputHal notify sendMessage"+event->type);
thiz->mLooper->sendMessage(new NotifyHandler(thiz, event), event->type);
}
void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
switch (mEvent.type) {
case TV_INPUT_EVENT_DEVICE_AVAILABLE: {
mHal->onDeviceAvailable(mEvent.device_info);
} break;
case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
ALOGE("TV_INPUT_EVENT_DEVICE_UNAVAILABLE device_id"+mEvent.device_info.device_id);
mHal->onDeviceUnavailable(mEvent.device_info.device_id);
} break;
case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: {
mHal->onStreamConfigurationsChanged(mEvent.device_info.device_id);
} break;
case TV_INPUT_EVENT_CAPTURE_SUCCEEDED: {
mHal->onCaptured(mEvent.capture_result.device_id,
mEvent.capture_result.stream_id,
mEvent.capture_result.seq,
true );
} break;
case TV_INPUT_EVENT_CAPTURE_FAILED: {
mHal->onCaptured(mEvent.capture_result.device_id,
mEvent.capture_result.stream_id,
mEvent.capture_result.seq,
false );
} break;
default:
ALOGE("Unrecognizable event");
}
}
走到这, case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: {
ALOGE("TV_INPUT_EVENT_DEVICE_UNAVAILABLE device_id"+mEvent.device_info.device_id);
mHal->onDeviceUnavailable(mEvent.device_info.device_id);
} break;
void JTvInputHal::onDeviceUnavailable(int deviceId) {
{
Mutex::Autolock autoLock(&mLock);
KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
for (size_t i = 0; i < connections.size(); ++i) {
removeStream(deviceId, connections.keyAt(i));
}
connections.clear();
mConnections.removeItem(deviceId);
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
ALOGE("JTvInputHal onDeviceUnavailable"+deviceId);
env->CallVoidMethod(
mThiz,
gTvInputHalClassInfo.deviceUnavailable,
deviceId);
}
ET_METHOD_ID(
gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V");
三,
frameworks/base/services/core/java/com/android/server/tv/TvInputHal.java
private void deviceUnavailableFromNative(int deviceId) {
Slog.e(TAG, "deviceUnavailableFromNative"+deviceId);
mHandler.obtainMessage(EVENT_DEVICE_UNAVAILABLE, deviceId, 0).sendToTarget();
}
public boolean handleMessage(Message msg) {
switch (msg.what) {
case EVENT_DEVICE_AVAILABLE: {
TvStreamConfig[] configs;
TvInputHardwareInfo info = (TvInputHardwareInfo)msg.obj;
synchronized (mLock) {
retrieveStreamConfigsLocked(info.getDeviceId());
if (DEBUG) {
Slog.d(TAG, "EVENT_DEVICE_AVAILABLE: info = " + info);
}
configs = mStreamConfigs.get(info.getDeviceId());
}
mCallback.onDeviceAvailable(info, configs);
break;
}
case EVENT_DEVICE_UNAVAILABLE: {
int deviceId = msg.arg1;
if (DEBUG) {
Slog.d(TAG, "EVENT_DEVICE_UNAVAILABLE: deviceId = " + deviceId);
}
mCallback.onDeviceUnavailable(deviceId);
break;
}
mCallback.onDeviceUnavailable
四, frameworks/base/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@Override
public void onDeviceUnavailable(int deviceId) {
synchronized (mLock) {
Connection connection = mConnections.get(deviceId);
if (connection == null) {
Slog.e(TAG, "onDeviceUnavailable: Cannot find a connection with " + deviceId);
return;
}
connection.resetLocked(null, null, null, null, null);
mConnections.remove(deviceId);
buildHardwareListLocked();
TvInputHardwareInfo info = connection.getHardwareInfoLocked();
if (info.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) {
// Remove HDMI devices linked with this hardware.
for (Iterator<HdmiDeviceInfo> it = mHdmiDeviceList.iterator(); it.hasNext();) {
HdmiDeviceInfo deviceInfo = it.next();
if (deviceInfo.getPortId() == info.getHdmiPortId()) {
Slog.e(TAG, "onDeviceUnavailable HDMI_DEVICE_REMOVED");
mHandler.obtainMessage(ListenerHandler.HDMI_DEVICE_REMOVED, 0, 0,
deviceInfo).sendToTarget();
it.remove();
}
}
}
Slog.e(TAG, "onDeviceUnavailable HARDWARE_DEVICE_REMOVED"+deviceId);
mHandler.obtainMessage(
ListenerHandler.HARDWARE_DEVICE_REMOVED, 0, 0, info).sendToTarget();
}
}
@Override
public final void handleMessage(Message msg) {
switch (msg.what) {
case STATE_CHANGED: {
String inputId = (String) msg.obj;
int state = msg.arg1;
mListener.onStateChanged(inputId, state);
break;
}
case HARDWARE_DEVICE_ADDED: {
TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj;
mListener.onHardwareDeviceAdded(info);
break;
}
case HARDWARE_DEVICE_REMOVED: {
Slog.e(TAG, "HARDWARE_DEVICE_REMOVED " );
TvInputHardwareInfo info = (TvInputHardwareInfo) msg.obj;
mListener.onHardwareDeviceRemoved(info);
break;
}
五,frameworks/base$ vi services/core/java/com/android/server/tv/TvInputManagerService.java
@Override
public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
synchronized (mLock) {
UserState userState = getUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
if (!serviceState.isHardware || serviceState.service == null) continue;
try {
Slog.e(TAG, "onHardwareDeviceRemoved");
serviceState.service.notifyHardwareRemoved(info);
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareRemoved", e);
}
}
}
}
六 frameworks/base$ vim media/java/android/media/tv/TvInputService.java
@Override
public void notifyHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
Log.e(TAG, "notifyHardwareRemoved ");
mServiceHandler.obtainMessage(ServiceHandler.DO_REMOVE_HARDWARE_TV_INPUT,
hardwareInfo).sendToTarget();
}
case DO_REMOVE_HARDWARE_TV_INPUT: {
TvInputHardwareInfo hardwareInfo = (TvInputHardwareInfo) msg.obj;
String inputId = onHardwareRemoved(hardwareInfo);
Log.e(TAG, "DO_REMOVE_HARDWARE_TV_INPUT inputId "+ inputId);
if (inputId != null) {
broadcastRemoveTvInput(inputId);
}
return;
}
private void broadcastRemoveTvInput(String inputId) {
int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; ++i) {
try {
mCallbacks.getBroadcastItem(i).removeTvInput(inputId);
} catch (RemoteException e) {
Log.e(TAG, "Error while broadcasting.", e);
}
}
mCallbacks.finishBroadcast();
}
frameworks/base$ vim services/core/java/com/android/server/tv/TvInputManagerService.java
@Override
public void removeTvInput(String inputId) {
ensureHardwarePermission();
synchronized (mLock) {
ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
boolean removed = false;
for (Iterator<TvInputInfo> it = serviceState.inputList.iterator();
it.hasNext(); ) {
if (it.next().getId().equals(inputId)) {
it.remove();
if(DEBUG){
Slog.d(TAG, "removeTvInput true");
}
removed = true;
// break; //鍉\═VInputService琚~][email protected]姝婚~G~M鍉P~P~N锛~LServiceState涓~Z~DinputList涓縹X瀛~X鍉\ㄧ~][email protected]鎫Wх~Z~D鎫U版~M紐L濡~B鎫^~\姝ゅDbreak浼~Z鎫\~I鍉H| 涓~M骞插[email protected]鐍Z~D鎫C~E鍉F碉紐L浠~N鑯@~L瀵艰~G寸~J舵[email protected]~A閪WX
}
}
if (removed) {
buildTvInputListLocked(mUserId, null);
Slog.e(TAG, "removeTvInput "+inputId);
mTvInputHardwareManager.removeTvInput(inputId);
} else {
Slog.e(TAG, "failed to remove input " + inputId);
}
}
}
}
private void buildTvInputListLocked(int userId, String[] updatedPackages) {
UserState userState = getUserStateLocked(userId);
userState.packageSet.clear();
if (DEBUG) Slog.d(TAG, "buildTvInputList");
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> services = pm.queryIntentServices(
new Intent(TvInputService.SERVICE_INTERFACE),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
List<TvInputInfo> inputList = new ArrayList<TvInputInfo>();
for (ResolveInfo ri : services) {
ServiceInfo si = ri.serviceInfo;
if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
Slog.w(TAG, "Skipping TV input " + si.name + ": it does not require the permission "
+ android.Manifest.permission.BIND_TV_INPUT);
continue;
}
ComponentName component = new ComponentName(si.packageName, si.name);
if (hasHardwarePermission(pm, component)) {
ServiceState serviceState = userState.serviceStateMap.get(component);
if (serviceState == null) {
// We see this hardware TV input service for the first time; we need to
// prepare the ServiceState object so that we can connect to the service and
// let it add TvInputInfo objects to mInputList if there's any.
serviceState = new ServiceState(component, userId);
userState.serviceStateMap.put(component, serviceState);
updateServiceConnectionLocked(component, userId);
} else {
inputList.addAll(serviceState.inputList);
}
} else {
try {
inputList.add(TvInputInfo.createTvInputInfo(mContext, ri));
} catch (XmlPullParserException | IOException e) {
Slog.e(TAG, "failed to load TV input " + si.name, e);
continue;
}
}
userState.packageSet.add(si.packageName);
}
Map<String, TvInputState> inputMap = new HashMap<String, TvInputState>();
for (TvInputInfo info : inputList) {
if (DEBUG) {
Slog.d(TAG, "add " + info.getId());
}
TvInputState state = userState.inputMap.get(info.getId());
if (state == null) {
state = new TvInputState();
}
state.info = info;
inputMap.put(info.getId(), state);
}
for (String inputId : inputMap.keySet()) {
if (!userState.inputMap.containsKey(inputId)) {
notifyInputAddedLocked(userState, inputId);
} else if (updatedPackages != null) {
// Notify the package updates
ComponentName component = inputMap.get(inputId).info.getComponent();
for (String updatedPackage : updatedPackages) {
if (component.getPackageName().equals(updatedPackage)) {
updateServiceConnectionLocked(component, userId);
Slog.e(TAG, "notifyInputUpdatedLocked 0 ");
notifyInputUpdatedLocked(userState, inputId);
break;
}
}
}
}
for (String inputId : userState.inputMap.keySet()) {
if (!inputMap.containsKey(inputId)) {
TvInputInfo info = userState.inputMap.get(inputId).info;
ServiceState serviceState = userState.serviceStateMap.get(info.getComponent());
if (serviceState != null) {
abortPendingCreateSessionRequestsLocked(serviceState, inputId, userId);
}
Slog.e(TAG, "notifyInputRemovedLocked 1 ");
notifyInputRemovedLocked(userState, inputId);
}
}
userState.inputMap.clear();
userState.inputMap = inputMap;
}
private void notifyInputRemovedLocked(UserState userState, String inputId) {
if (DEBUG) {
Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")");
}
for (ITvInputManagerCallback callback : userState.callbackSet) {
try {
callback.onInputRemoved(inputId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report removed input to callback", e);
}
}
}
七, app层注册callback
private TvInputManager.TvInputCallback callback = new TvInputManager.TvInputCallback() {
@Override
public void onInputStateChanged(String inputId, int state) {
super.onInputStateChanged(inputId, state);
}
@Override
public void onInputAdded(String inputId) {
super.onInputAdded(inputId);
L.d(TAG, "onInputAdded inputId=" + inputId);
TvInputInfo inputAdded = mTvInputManager.getTvInputInfo(inputId);
if (inputAdded != null && (mInputDevices.size() == 0 || mInputDevices.size() > 0 && !mInputDevices.contains(inputAdded))) {
mInputDevices.add(inputAdded);
}
L.d(TAG, "onInputAdded mInputDevices.size=" + mInputDevices.size());
invalidDeviceState(true);
}
@Override
public void onInputRemoved(String inputId) {
super.onInputRemoved(inputId);
L.d(TAG, "onInputRemoved inputId=" + inputId);
TvInputInfo inputInfo;
Iterator<TvInputInfo> iterator = mInputDevices.iterator();
while (iterator.hasNext()) {
inputInfo = iterator.next();
if (inputInfo.getId().equals(inputId)) {
iterator.remove();
}
}
L.d(TAG, "onInputRemoved mInputDevices.size=" + mInputDevices.size());
invalidDeviceState(true);
}
};