Merge "Bind the hardware TIS only when needed" into main
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index b384725..92b5764 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -309,6 +309,24 @@
}
}
+ public SparseArray<String> getHardwareInputIdMap() {
+ synchronized (mLock) {
+ return mHardwareInputIdMap.clone();
+ }
+ }
+
+ public SparseArray<String> getHdmiInputIdMap() {
+ synchronized (mLock) {
+ return mHdmiInputIdMap.clone();
+ }
+ }
+
+ public Map<String, TvInputInfo> getInputMap() {
+ synchronized (mLock) {
+ return Collections.unmodifiableMap(mInputMap);
+ }
+ }
+
public Map<String, List<String>> getHdmiParentInputMap() {
synchronized (mLock) {
return Collections.unmodifiableMap(mHdmiParentInputMap);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index ac1b4df..e434df7 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -135,6 +135,7 @@
private static final int APP_TAG_SELF = TunedInfo.APP_TAG_SELF;
private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS =
"com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS";
+ private static final long UPDATE_HARDWARE_TIS_BINDING_DELAY_IN_MILLIS = 10 * 1000; // 10 seconds
// There are two different formats of DVB frontend devices. One is /dev/dvb%d.frontend%d,
// another one is /dev/dvb/adapter%d/frontend%d. Followings are the patterns for selecting the
@@ -174,7 +175,7 @@
@GuardedBy("mLock")
private final Map<String, SessionState> mSessionIdToSessionStateMap = new HashMap<>();
- private final WatchLogHandler mWatchLogHandler;
+ private final MessageHandler mMessageHandler;
private final ActivityManager mActivityManager;
@@ -187,8 +188,8 @@
super(context);
mContext = context;
- mWatchLogHandler = new WatchLogHandler(mContext.getContentResolver(),
- IoThread.get().getLooper());
+ mMessageHandler =
+ new MessageHandler(mContext.getContentResolver(), IoThread.get().getLooper());
mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
mActivityManager =
@@ -372,10 +373,10 @@
// service to populate the hardware list.
serviceState = new ServiceState(component, userId);
userState.serviceStateMap.put(component, serviceState);
+ updateServiceConnectionLocked(component, userId);
} else {
inputList.addAll(serviceState.hardwareInputMap.values());
}
- updateServiceConnectionLocked(component, userId);
} else {
try {
TvInputInfo info = new TvInputInfo.Builder(mContext, ri).build();
@@ -510,6 +511,7 @@
}
}
+ @GuardedBy("mLock")
private void startProfileLocked(int userId) {
mRunningProfiles.add(userId);
buildTvInputListLocked(userId, null);
@@ -538,8 +540,10 @@
mCurrentUserId = userId;
buildTvInputListLocked(userId, null);
buildTvContentRatingSystemListLocked(userId);
- mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_SWITCH_CONTENT_RESOLVER,
- getContentResolverForUser(userId)).sendToTarget();
+ mMessageHandler
+ .obtainMessage(MessageHandler.MSG_SWITCH_CONTENT_RESOLVER,
+ getContentResolverForUser(userId))
+ .sendToTarget();
}
}
@@ -593,7 +597,7 @@
Slog.e(TAG, "error in unregisterCallback", e);
}
}
- mContext.unbindService(serviceState.connection);
+ unbindService(serviceState);
it.remove();
}
}
@@ -661,7 +665,7 @@
Slog.e(TAG, "error in unregisterCallback", e);
}
}
- mContext.unbindService(serviceState.connection);
+ unbindService(serviceState);
}
}
userState.serviceStateMap.clear();
@@ -774,7 +778,8 @@
boolean shouldBind;
if (userId == mCurrentUserId || mRunningProfiles.contains(userId)) {
- shouldBind = !serviceState.sessionTokens.isEmpty() || serviceState.isHardware;
+ shouldBind = !serviceState.sessionTokens.isEmpty()
+ || (serviceState.isHardware && serviceState.neverConnected);
} else {
// For a non-current user,
// if sessionTokens is not empty, it contains recording sessions only
@@ -783,31 +788,14 @@
shouldBind = !serviceState.sessionTokens.isEmpty();
}
- if (serviceState.service == null && shouldBind) {
- // This means that the service is not yet connected but its state indicates that we
- // have pending requests. Then, connect the service.
- if (serviceState.bound) {
- // We have already bound to the service so we don't try to bind again until after we
- // unbind later on.
- return;
+ // only bind/unbind when necessary.
+ if (shouldBind && !serviceState.bound) {
+ bindService(serviceState, userId);
+ } else if (!shouldBind && serviceState.bound) {
+ unbindService(serviceState);
+ if (!serviceState.isHardware) {
+ userState.serviceStateMap.remove(component);
}
- if (DEBUG) {
- Slog.d(TAG, "bindServiceAsUser(service=" + component + ", userId=" + userId + ")");
- }
-
- Intent i = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
- serviceState.bound = mContext.bindServiceAsUser(
- i, serviceState.connection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
- new UserHandle(userId));
- } else if (serviceState.service != null && !shouldBind) {
- // This means that the service is already connected but its state indicates that we have
- // nothing to do with it. Then, disconnect the service.
- if (DEBUG) {
- Slog.d(TAG, "unbindService(service=" + component + ")");
- }
- mContext.unbindService(serviceState.connection);
- userState.serviceStateMap.remove(component);
}
}
@@ -829,7 +817,11 @@
sendSessionTokenToClientLocked(sessionState.client,
sessionState.inputId, null, null, sessionState.seq);
}
- updateServiceConnectionLocked(serviceState.component, userId);
+ if (!serviceState.isHardware) {
+ updateServiceConnectionLocked(serviceState.component, userId);
+ } else {
+ updateHardwareServiceConnectionDelayed(userId);
+ }
}
@GuardedBy("mLock")
@@ -948,13 +940,17 @@
if (serviceState != null) {
serviceState.sessionTokens.remove(sessionToken);
}
- updateServiceConnectionLocked(sessionState.componentName, userId);
+ if (!serviceState.isHardware) {
+ updateServiceConnectionLocked(sessionState.componentName, userId);
+ } else {
+ updateHardwareServiceConnectionDelayed(userId);
+ }
// Log the end of watch.
SomeArgs args = SomeArgs.obtain();
args.arg1 = sessionToken;
args.arg2 = System.currentTimeMillis();
- mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_END, args).sendToTarget();
+ mMessageHandler.obtainMessage(MessageHandler.MSG_LOG_WATCH_END, args).sendToTarget();
}
@GuardedBy("mLock")
@@ -1153,8 +1149,7 @@
ServiceState serviceState = userState.serviceStateMap.get(inputState.info.getComponent());
int oldState = inputState.state;
inputState.state = state;
- if (serviceState != null && serviceState.service == null
- && (!serviceState.sessionTokens.isEmpty() || serviceState.isHardware)) {
+ if (serviceState != null && serviceState.reconnecting) {
// We don't notify state change while reconnecting. It should remain disconnected.
return;
}
@@ -1881,7 +1876,7 @@
args.arg3 = ContentUris.parseId(channelUri);
args.arg4 = params;
args.arg5 = sessionToken;
- mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
+ mMessageHandler.obtainMessage(MessageHandler.MSG_LOG_WATCH_START, args)
.sendToTarget();
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in tune", e);
@@ -3327,16 +3322,21 @@
private final ComponentName component;
private final boolean isHardware;
private final Map<String, TvInputInfo> hardwareInputMap = new HashMap<>();
+ private final List<TvInputHardwareInfo> hardwareDeviceRemovedBuffer = new ArrayList<>();
+ private final List<HdmiDeviceInfo> hdmiDeviceRemovedBuffer = new ArrayList<>();
+ private final List<HdmiDeviceInfo> hdmiDeviceUpdatedBuffer = new ArrayList<>();
private ITvInputService service;
private ServiceCallback callback;
private boolean bound;
private boolean reconnecting;
+ private boolean neverConnected;
private ServiceState(ComponentName component, int userId) {
this.component = component;
this.connection = new InputServiceConnection(component, userId);
this.isHardware = hasHardwarePermission(mContext.getPackageManager(), component);
+ this.neverConnected = true;
}
}
@@ -3449,6 +3449,97 @@
}
}
+ @GuardedBy("mLock")
+ private void bindService(ServiceState serviceState, int userId) {
+ if (serviceState.bound) {
+ // We have already bound to the service so we don't try to bind again until after we
+ // unbind later on.
+ // For hardware services, call updateHardwareServiceConnectionDelayed() to delay the
+ // possible unbinding.
+ if (serviceState.isHardware) {
+ updateHardwareServiceConnectionDelayed(userId);
+ }
+ return;
+ }
+ if (DEBUG) {
+ Slog.d(TAG,
+ "bindServiceAsUser(service=" + serviceState.component + ", userId=" + userId
+ + ")");
+ }
+ Intent i =
+ new Intent(TvInputService.SERVICE_INTERFACE).setComponent(serviceState.component);
+ serviceState.bound = mContext.bindServiceAsUser(i, serviceState.connection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ new UserHandle(userId));
+ if (!serviceState.bound) {
+ Slog.e(TAG, "failed to bind " + serviceState.component + " for userId " + userId);
+ mContext.unbindService(serviceState.connection);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void unbindService(ServiceState serviceState) {
+ if (!serviceState.bound) {
+ return;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "unbindService(service=" + serviceState.component + ")");
+ }
+ mContext.unbindService(serviceState.connection);
+ serviceState.bound = false;
+ serviceState.service = null;
+ serviceState.callback = null;
+ }
+
+ @GuardedBy("mLock")
+ private void updateHardwareTvInputServiceBindingLocked(int userId) {
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> services =
+ pm.queryIntentServicesAsUser(new Intent(TvInputService.SERVICE_INTERFACE),
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, userId);
+ for (ResolveInfo ri : services) {
+ ServiceInfo si = ri.serviceInfo;
+ if (!android.Manifest.permission.BIND_TV_INPUT.equals(si.permission)) {
+ continue;
+ }
+ ComponentName component = new ComponentName(si.packageName, si.name);
+ if (hasHardwarePermission(pm, component)) {
+ updateServiceConnectionLocked(component, userId);
+ }
+ }
+ }
+
+ private void updateHardwareServiceConnectionDelayed(int userId) {
+ mMessageHandler.removeMessages(MessageHandler.MSG_UPDATE_HARDWARE_TIS_BINDING);
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = userId;
+ Message msg =
+ mMessageHandler.obtainMessage(MessageHandler.MSG_UPDATE_HARDWARE_TIS_BINDING, args);
+ mMessageHandler.sendMessageDelayed(msg, UPDATE_HARDWARE_TIS_BINDING_DELAY_IN_MILLIS);
+ }
+
+ @GuardedBy("mLock")
+ private void addHardwareInputLocked(
+ TvInputInfo inputInfo, ComponentName component, int userId) {
+ ServiceState serviceState = getServiceStateLocked(component, userId);
+ serviceState.hardwareInputMap.put(inputInfo.getId(), inputInfo);
+ buildTvInputListLocked(userId, null);
+ }
+
+ @GuardedBy("mLock")
+ private void removeHardwareInputLocked(String inputId, int userId) {
+ if (!mTvInputHardwareManager.getInputMap().containsKey(inputId)) {
+ return;
+ }
+ ComponentName component = mTvInputHardwareManager.getInputMap().get(inputId).getComponent();
+ ServiceState serviceState = getServiceStateLocked(component, userId);
+ boolean removed = serviceState.hardwareInputMap.remove(inputId) != null;
+ if (removed) {
+ buildTvInputListLocked(userId, null);
+ mTvInputHardwareManager.removeHardwareInput(inputId);
+ }
+ }
+
private final class InputServiceConnection implements ServiceConnection {
private final ComponentName mComponent;
private final int mUserId;
@@ -3472,6 +3563,7 @@
}
ServiceState serviceState = userState.serviceStateMap.get(mComponent);
serviceState.service = ITvInputService.Stub.asInterface(service);
+ serviceState.neverConnected = false;
// Register a callback, if we need to.
if (serviceState.isHardware && serviceState.callback == null) {
@@ -3483,6 +3575,58 @@
}
}
+ for (TvInputState inputState : userState.inputMap.values()) {
+ if (inputState.info.getComponent().equals(component)
+ && inputState.state != INPUT_STATE_CONNECTED) {
+ notifyInputStateChangedLocked(userState, inputState.info.getId(),
+ inputState.state, null);
+ }
+ }
+
+ if (serviceState.isHardware) {
+ for (TvInputHardwareInfo hardwareToBeRemoved :
+ serviceState.hardwareDeviceRemovedBuffer) {
+ try {
+ serviceState.service.notifyHardwareRemoved(hardwareToBeRemoved);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in hardwareDeviceRemovedBuffer", e);
+ }
+ }
+ serviceState.hardwareDeviceRemovedBuffer.clear();
+ for (HdmiDeviceInfo hdmiDeviceToBeRemoved :
+ serviceState.hdmiDeviceRemovedBuffer) {
+ try {
+ serviceState.service.notifyHdmiDeviceRemoved(hdmiDeviceToBeRemoved);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in hdmiDeviceRemovedBuffer", e);
+ }
+ }
+ serviceState.hdmiDeviceRemovedBuffer.clear();
+ for (TvInputHardwareInfo hardware : mTvInputHardwareManager.getHardwareList()) {
+ try {
+ serviceState.service.notifyHardwareAdded(hardware);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in notifyHardwareAdded", e);
+ }
+ }
+ for (HdmiDeviceInfo device : mTvInputHardwareManager.getHdmiDeviceList()) {
+ try {
+ serviceState.service.notifyHdmiDeviceAdded(device);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
+ }
+ }
+ for (HdmiDeviceInfo hdmiDeviceToBeUpdated :
+ serviceState.hdmiDeviceUpdatedBuffer) {
+ try {
+ serviceState.service.notifyHdmiDeviceUpdated(hdmiDeviceToBeUpdated);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "error in hdmiDeviceUpdatedBuffer", e);
+ }
+ }
+ serviceState.hdmiDeviceUpdatedBuffer.clear();
+ }
+
List<IBinder> tokensToBeRemoved = new ArrayList<>();
// And create sessions, if any.
@@ -3496,30 +3640,8 @@
removeSessionStateLocked(sessionToken, mUserId);
}
- for (TvInputState inputState : userState.inputMap.values()) {
- if (inputState.info.getComponent().equals(component)
- && inputState.state != INPUT_STATE_CONNECTED) {
- notifyInputStateChangedLocked(userState, inputState.info.getId(),
- inputState.state, null);
- }
- }
-
if (serviceState.isHardware) {
- serviceState.hardwareInputMap.clear();
- for (TvInputHardwareInfo hardware : mTvInputHardwareManager.getHardwareList()) {
- try {
- serviceState.service.notifyHardwareAdded(hardware);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in notifyHardwareAdded", e);
- }
- }
- for (HdmiDeviceInfo device : mTvInputHardwareManager.getHdmiDeviceList()) {
- try {
- serviceState.service.notifyHdmiDeviceAdded(device);
- } catch (RemoteException e) {
- Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
- }
- }
+ updateHardwareServiceConnectionDelayed(mUserId);
}
}
}
@@ -3570,13 +3692,6 @@
}
}
- @GuardedBy("mLock")
- private void addHardwareInputLocked(TvInputInfo inputInfo) {
- ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
- serviceState.hardwareInputMap.put(inputInfo.getId(), inputInfo);
- buildTvInputListLocked(mUserId, null);
- }
-
public void addHardwareInput(int deviceId, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
@@ -3587,8 +3702,11 @@
if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
return;
}
+ Slog.d("ServiceCallback",
+ "addHardwareInput: device id " + deviceId + ", "
+ + inputInfo.toString());
mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
- addHardwareInputLocked(inputInfo);
+ addHardwareInputLocked(inputInfo, mComponent, mUserId);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -3606,7 +3724,7 @@
return;
}
mTvInputHardwareManager.addHdmiInput(id, inputInfo);
- addHardwareInputLocked(inputInfo);
+ addHardwareInputLocked(inputInfo, mComponent, mUserId);
if (mOnScreenInputId != null && mOnScreenSessionState != null) {
if (TextUtils.equals(mOnScreenInputId, inputInfo.getParentId())) {
// catch the use case when a CEC device is plugged in an HDMI port,
@@ -3635,14 +3753,9 @@
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
- boolean removed = serviceState.hardwareInputMap.remove(inputId) != null;
- if (removed) {
- buildTvInputListLocked(mUserId, null);
- mTvInputHardwareManager.removeHardwareInput(inputId);
- } else {
- Slog.e(TAG, "failed to remove input " + inputId);
- }
+ Slog.d("ServiceCallback",
+ "removeHardwareInput " + inputId + " by " + mComponent);
+ removeHardwareInputLocked(inputId, mUserId);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -4226,11 +4339,12 @@
return loggedReason;
}
+ @GuardedBy("mLock")
private UserState getUserStateLocked(int userId) {
return mUserStates.get(userId);
}
- private static final class WatchLogHandler extends Handler {
+ private final class MessageHandler extends Handler {
// There are only two kinds of watch events that can happen on the system:
// 1. The current TV input session is tuned to a new channel.
// 2. The session is released for some reason.
@@ -4242,10 +4356,11 @@
static final int MSG_LOG_WATCH_START = 1;
static final int MSG_LOG_WATCH_END = 2;
static final int MSG_SWITCH_CONTENT_RESOLVER = 3;
+ static final int MSG_UPDATE_HARDWARE_TIS_BINDING = 4;
private ContentResolver mContentResolver;
- WatchLogHandler(ContentResolver contentResolver, Looper looper) {
+ MessageHandler(ContentResolver contentResolver, Looper looper) {
super(looper);
mContentResolver = contentResolver;
}
@@ -4304,6 +4419,14 @@
mContentResolver = (ContentResolver) msg.obj;
break;
}
+ case MSG_UPDATE_HARDWARE_TIS_BINDING:
+ SomeArgs args = (SomeArgs) msg.obj;
+ int userId = (int) args.arg1;
+ synchronized (mLock) {
+ updateHardwareTvInputServiceBindingLocked(userId);
+ }
+ args.recycle();
+ break;
default: {
Slog.w(TAG, "unhandled message code: " + msg.what);
break;
@@ -4359,29 +4482,46 @@
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (!serviceState.isHardware || serviceState.service == null) continue;
+ if (!serviceState.isHardware) {
+ continue;
+ }
try {
- serviceState.service.notifyHardwareAdded(info);
+ bindService(serviceState, mCurrentUserId);
+ if (serviceState.service != null) {
+ serviceState.service.notifyHardwareAdded(info);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareAdded", e);
}
}
+ updateHardwareServiceConnectionDelayed(mCurrentUserId);
}
}
@Override
public void onHardwareDeviceRemoved(TvInputHardwareInfo info) {
synchronized (mLock) {
+ String relatedInputId =
+ mTvInputHardwareManager.getHardwareInputIdMap().get(info.getDeviceId());
+ removeHardwareInputLocked(relatedInputId, mCurrentUserId);
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (!serviceState.isHardware || serviceState.service == null) continue;
+ if (!serviceState.isHardware) {
+ continue;
+ }
try {
- serviceState.service.notifyHardwareRemoved(info);
+ bindService(serviceState, mCurrentUserId);
+ if (serviceState.service != null) {
+ serviceState.service.notifyHardwareRemoved(info);
+ } else {
+ serviceState.hardwareDeviceRemovedBuffer.add(info);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHardwareRemoved", e);
}
}
+ updateHardwareServiceConnectionDelayed(mCurrentUserId);
}
}
@@ -4391,29 +4531,46 @@
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (!serviceState.isHardware || serviceState.service == null) continue;
+ if (!serviceState.isHardware) {
+ continue;
+ }
try {
- serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
+ bindService(serviceState, mCurrentUserId);
+ if (serviceState.service != null) {
+ serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceAdded", e);
}
}
+ updateHardwareServiceConnectionDelayed(mCurrentUserId);
}
}
@Override
public void onHdmiDeviceRemoved(HdmiDeviceInfo deviceInfo) {
synchronized (mLock) {
+ String relatedInputId =
+ mTvInputHardwareManager.getHdmiInputIdMap().get(deviceInfo.getId());
+ removeHardwareInputLocked(relatedInputId, mCurrentUserId);
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (!serviceState.isHardware || serviceState.service == null) continue;
+ if (!serviceState.isHardware) {
+ continue;
+ }
try {
- serviceState.service.notifyHdmiDeviceRemoved(deviceInfo);
+ bindService(serviceState, mCurrentUserId);
+ if (serviceState.service != null) {
+ serviceState.service.notifyHdmiDeviceRemoved(deviceInfo);
+ } else {
+ serviceState.hdmiDeviceRemovedBuffer.add(deviceInfo);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceRemoved", e);
}
}
+ updateHardwareServiceConnectionDelayed(mCurrentUserId);
}
}
@@ -4441,13 +4598,21 @@
UserState userState = getOrCreateUserStateLocked(mCurrentUserId);
// Broadcast the event to all hardware inputs.
for (ServiceState serviceState : userState.serviceStateMap.values()) {
- if (!serviceState.isHardware || serviceState.service == null) continue;
+ if (!serviceState.isHardware) {
+ continue;
+ }
try {
- serviceState.service.notifyHdmiDeviceUpdated(deviceInfo);
+ bindService(serviceState, mCurrentUserId);
+ if (serviceState.service != null) {
+ serviceState.service.notifyHdmiDeviceUpdated(deviceInfo);
+ } else {
+ serviceState.hdmiDeviceUpdatedBuffer.add(deviceInfo);
+ }
} catch (RemoteException e) {
Slog.e(TAG, "error in notifyHdmiDeviceUpdated", e);
}
}
+ updateHardwareServiceConnectionDelayed(mCurrentUserId);
}
}