Merge "Tuner APIs: add locks to avoid crashes caused by NPE" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-07-15 18:59:10 +00:00
committed by Android (Google) Code Review
5 changed files with 186 additions and 107 deletions

View File

@@ -148,6 +148,7 @@ public class Lnb implements AutoCloseable {
LnbCallback mCallback; LnbCallback mCallback;
Executor mExecutor; Executor mExecutor;
Tuner mTuner; Tuner mTuner;
private final Object mCallbackLock = new Object();
private native int nativeSetVoltage(int voltage); private native int nativeSetVoltage(int voltage);
@@ -164,22 +165,28 @@ public class Lnb implements AutoCloseable {
private Lnb() {} private Lnb() {}
void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) { void setCallback(Executor executor, @Nullable LnbCallback callback, Tuner tuner) {
synchronized (mCallbackLock) {
mCallback = callback; mCallback = callback;
mExecutor = executor; mExecutor = executor;
mTuner = tuner; mTuner = tuner;
} }
}
private void onEvent(int eventType) { private void onEvent(int eventType) {
synchronized (mCallbackLock) {
if (mExecutor != null && mCallback != null) { if (mExecutor != null && mCallback != null) {
mExecutor.execute(() -> mCallback.onEvent(eventType)); mExecutor.execute(() -> mCallback.onEvent(eventType));
} }
} }
}
private void onDiseqcMessage(byte[] diseqcMessage) { private void onDiseqcMessage(byte[] diseqcMessage) {
synchronized (mCallbackLock) {
if (mExecutor != null && mCallback != null) { if (mExecutor != null && mCallback != null) {
mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage)); mExecutor.execute(() -> mCallback.onDiseqcMessage(diseqcMessage));
} }
} }
}
/* package */ boolean isClosed() { /* package */ boolean isClosed() {
synchronized (mLock) { synchronized (mLock) {

View File

@@ -291,7 +291,7 @@ public class Tuner implements AutoCloseable {
@Nullable @Nullable
private OnTuneEventListener mOnTuneEventListener; private OnTuneEventListener mOnTuneEventListener;
@Nullable @Nullable
private Executor mOnTunerEventExecutor; private Executor mOnTuneEventExecutor;
@Nullable @Nullable
private ScanCallback mScanCallback; private ScanCallback mScanCallback;
@Nullable @Nullable
@@ -301,6 +301,10 @@ public class Tuner implements AutoCloseable {
@Nullable @Nullable
private Executor mOnResourceLostListenerExecutor; private Executor mOnResourceLostListenerExecutor;
private final Object mOnTuneEventLock = new Object();
private final Object mScanCallbackLock = new Object();
private final Object mOnResourceLostListenerLock = new Object();
private Integer mDemuxHandle; private Integer mDemuxHandle;
private Integer mFrontendCiCamHandle; private Integer mFrontendCiCamHandle;
private Integer mFrontendCiCamId; private Integer mFrontendCiCamId;
@@ -398,19 +402,23 @@ public class Tuner implements AutoCloseable {
*/ */
public void setResourceLostListener(@NonNull @CallbackExecutor Executor executor, public void setResourceLostListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnResourceLostListener listener) { @NonNull OnResourceLostListener listener) {
synchronized (mOnResourceLostListenerLock) {
Objects.requireNonNull(executor, "OnResourceLostListener must not be null"); Objects.requireNonNull(executor, "OnResourceLostListener must not be null");
Objects.requireNonNull(listener, "executor must not be null"); Objects.requireNonNull(listener, "executor must not be null");
mOnResourceLostListener = listener; mOnResourceLostListener = listener;
mOnResourceLostListenerExecutor = executor; mOnResourceLostListenerExecutor = executor;
} }
}
/** /**
* Removes the listener for resource lost. * Removes the listener for resource lost.
*/ */
public void clearResourceLostListener() { public void clearResourceLostListener() {
synchronized (mOnResourceLostListenerLock) {
mOnResourceLostListener = null; mOnResourceLostListener = null;
mOnResourceLostListenerExecutor = null; mOnResourceLostListenerExecutor = null;
} }
}
/** /**
* Shares the frontend resource with another Tuner instance * Shares the frontend resource with another Tuner instance
@@ -618,11 +626,13 @@ public class Tuner implements AutoCloseable {
break; break;
} }
case MSG_RESOURCE_LOST: { case MSG_RESOURCE_LOST: {
synchronized (mOnResourceLostListenerLock) {
if (mOnResourceLostListener != null if (mOnResourceLostListener != null
&& mOnResourceLostListenerExecutor != null) { && mOnResourceLostListenerExecutor != null) {
mOnResourceLostListenerExecutor.execute( mOnResourceLostListenerExecutor.execute(
() -> mOnResourceLostListener.onResourceLost(Tuner.this)); () -> mOnResourceLostListener.onResourceLost(Tuner.this));
} }
}
break; break;
} }
default: default:
@@ -652,8 +662,10 @@ public class Tuner implements AutoCloseable {
*/ */
public void setOnTuneEventListener(@NonNull @CallbackExecutor Executor executor, public void setOnTuneEventListener(@NonNull @CallbackExecutor Executor executor,
@NonNull OnTuneEventListener eventListener) { @NonNull OnTuneEventListener eventListener) {
synchronized (mOnTuneEventLock) {
mOnTuneEventListener = eventListener; mOnTuneEventListener = eventListener;
mOnTunerEventExecutor = executor; mOnTuneEventExecutor = executor;
}
} }
/** /**
@@ -663,9 +675,10 @@ public class Tuner implements AutoCloseable {
* @see #setOnTuneEventListener(Executor, OnTuneEventListener) * @see #setOnTuneEventListener(Executor, OnTuneEventListener)
*/ */
public void clearOnTuneEventListener() { public void clearOnTuneEventListener() {
synchronized (mOnTuneEventLock) {
mOnTuneEventListener = null; mOnTuneEventListener = null;
mOnTunerEventExecutor = null; mOnTuneEventExecutor = null;
}
} }
/** /**
@@ -747,9 +760,9 @@ public class Tuner implements AutoCloseable {
@Result @Result
public int scan(@NonNull FrontendSettings settings, @ScanType int scanType, public int scan(@NonNull FrontendSettings settings, @ScanType int scanType,
@NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) { @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) {
/** synchronized (mScanCallbackLock) {
* Scan can be called again for blink scan if scanCallback and executor are same as before. // Scan can be called again for blink scan if scanCallback and executor are same as
*/ //before.
if (((mScanCallback != null) && (mScanCallback != scanCallback)) if (((mScanCallback != null) && (mScanCallback != scanCallback))
|| ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) { || ((mScanCallbackExecutor != null) && (mScanCallbackExecutor != executor))) {
throw new IllegalStateException( throw new IllegalStateException(
@@ -759,7 +772,8 @@ public class Tuner implements AutoCloseable {
mFrontendType = settings.getType(); mFrontendType = settings.getType();
if (mFrontendType == FrontendSettings.TYPE_DTMB) { if (mFrontendType == FrontendSettings.TYPE_DTMB) {
if (!TunerVersionChecker.checkHigherOrEqualVersionTo( if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
TunerVersionChecker.TUNER_VERSION_1_1, "Scan with DTMB Frontend")) { TunerVersionChecker.TUNER_VERSION_1_1,
"Scan with DTMB Frontend")) {
return RESULT_UNAVAILABLE; return RESULT_UNAVAILABLE;
} }
} }
@@ -774,6 +788,7 @@ public class Tuner implements AutoCloseable {
} }
return RESULT_UNAVAILABLE; return RESULT_UNAVAILABLE;
} }
}
/** /**
* Stops a previous scanning. * Stops a previous scanning.
@@ -788,8 +803,8 @@ public class Tuner implements AutoCloseable {
*/ */
@Result @Result
public int cancelScanning() { public int cancelScanning() {
FrameworkStatsLog synchronized (mScanCallbackLock) {
.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, FrameworkStatsLog.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCAN_STOPPED); FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__SCAN_STOPPED);
int retVal = nativeStopScan(); int retVal = nativeStopScan();
@@ -797,6 +812,7 @@ public class Tuner implements AutoCloseable {
mScanCallbackExecutor = null; mScanCallbackExecutor = null;
return retVal; return retVal;
} }
}
private boolean requestFrontend() { private boolean requestFrontend() {
int[] feHandle = new int[1]; int[] feHandle = new int[1];
@@ -1050,8 +1066,10 @@ public class Tuner implements AutoCloseable {
private void onFrontendEvent(int eventType) { private void onFrontendEvent(int eventType) {
Log.d(TAG, "Got event from tuning. Event type: " + eventType); Log.d(TAG, "Got event from tuning. Event type: " + eventType);
if (mOnTunerEventExecutor != null && mOnTuneEventListener != null) { synchronized (mOnTuneEventLock) {
mOnTunerEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType)); if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) {
mOnTuneEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType));
}
} }
Log.d(TAG, "Wrote Stats Log for the events from tuning."); Log.d(TAG, "Wrote Stats Log for the events from tuning.");
@@ -1072,116 +1090,151 @@ public class Tuner implements AutoCloseable {
private void onLocked() { private void onLocked() {
Log.d(TAG, "Wrote Stats Log for locked event from scanning."); Log.d(TAG, "Wrote Stats Log for locked event from scanning.");
FrameworkStatsLog FrameworkStatsLog.write(
.write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId,
FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED); FrameworkStatsLog.TV_TUNER_STATE_CHANGED__STATE__LOCKED);
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onLocked()); mScanCallbackExecutor.execute(() -> mScanCallback.onLocked());
} }
} }
}
private void onScanStopped() { private void onScanStopped() {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped()); mScanCallbackExecutor.execute(() -> mScanCallback.onScanStopped());
} }
} }
}
private void onProgress(int percent) { private void onProgress(int percent) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent)); mScanCallbackExecutor.execute(() -> mScanCallback.onProgress(percent));
} }
} }
}
private void onFrequenciesReport(int[] frequency) { private void onFrequenciesReport(int[] frequency) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency)); mScanCallbackExecutor.execute(() -> mScanCallback.onFrequenciesReported(frequency));
} }
} }
}
private void onSymbolRates(int[] rate) { private void onSymbolRates(int[] rate) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate)); mScanCallbackExecutor.execute(() -> mScanCallback.onSymbolRatesReported(rate));
} }
} }
}
private void onHierarchy(int hierarchy) { private void onHierarchy(int hierarchy) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy)); mScanCallbackExecutor.execute(() -> mScanCallback.onHierarchyReported(hierarchy));
} }
} }
}
private void onSignalType(int signalType) { private void onSignalType(int signalType) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType)); mScanCallbackExecutor.execute(() -> mScanCallback.onSignalTypeReported(signalType));
} }
} }
}
private void onPlpIds(int[] plpIds) { private void onPlpIds(int[] plpIds) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds)); mScanCallbackExecutor.execute(() -> mScanCallback.onPlpIdsReported(plpIds));
} }
} }
}
private void onGroupIds(int[] groupIds) { private void onGroupIds(int[] groupIds) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds)); mScanCallbackExecutor.execute(() -> mScanCallback.onGroupIdsReported(groupIds));
} }
} }
}
private void onInputStreamIds(int[] inputStreamIds) { private void onInputStreamIds(int[] inputStreamIds) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute( mScanCallbackExecutor.execute(
() -> mScanCallback.onInputStreamIdsReported(inputStreamIds)); () -> mScanCallback.onInputStreamIdsReported(inputStreamIds));
} }
} }
}
private void onDvbsStandard(int dvbsStandandard) { private void onDvbsStandard(int dvbsStandandard) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute( mScanCallbackExecutor.execute(
() -> mScanCallback.onDvbsStandardReported(dvbsStandandard)); () -> mScanCallback.onDvbsStandardReported(dvbsStandandard));
} }
} }
}
private void onDvbtStandard(int dvbtStandard) { private void onDvbtStandard(int dvbtStandard) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onDvbtStandardReported(dvbtStandard)); mScanCallbackExecutor.execute(
() -> mScanCallback.onDvbtStandardReported(dvbtStandard));
}
} }
} }
private void onAnalogSifStandard(int sif) { private void onAnalogSifStandard(int sif) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif)); mScanCallbackExecutor.execute(() -> mScanCallback.onAnalogSifStandardReported(sif));
} }
} }
}
private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) { private void onAtsc3PlpInfos(Atsc3PlpInfo[] atsc3PlpInfos) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute( mScanCallbackExecutor.execute(
() -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos)); () -> mScanCallback.onAtsc3PlpInfosReported(atsc3PlpInfos));
} }
} }
}
private void onModulationReported(int modulation) { private void onModulationReported(int modulation) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute( mScanCallbackExecutor.execute(
() -> mScanCallback.onModulationReported(modulation)); () -> mScanCallback.onModulationReported(modulation));
} }
} }
}
private void onPriorityReported(boolean isHighPriority) { private void onPriorityReported(boolean isHighPriority) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute( mScanCallbackExecutor.execute(
() -> mScanCallback.onPriorityReported(isHighPriority)); () -> mScanCallback.onPriorityReported(isHighPriority));
} }
} }
}
private void onDvbcAnnexReported(int dvbcAnnex) { private void onDvbcAnnexReported(int dvbcAnnex) {
synchronized (mScanCallbackLock) {
if (mScanCallbackExecutor != null && mScanCallback != null) { if (mScanCallbackExecutor != null && mScanCallback != null) {
mScanCallbackExecutor.execute( mScanCallbackExecutor.execute(
() -> mScanCallback.onDvbcAnnexReported(dvbcAnnex)); () -> mScanCallback.onDvbcAnnexReported(dvbcAnnex));
} }
} }
}
/** /**
* Opens a filter object based on the given types and buffer size. * Opens a filter object based on the given types and buffer size.

View File

@@ -85,6 +85,7 @@ public class DvrPlayback implements AutoCloseable {
private static int sInstantId = 0; private static int sInstantId = 0;
private int mSegmentId = 0; private int mSegmentId = 0;
private int mUnderflow; private int mUnderflow;
private final Object mListenerLock = new Object();
private native int nativeAttachFilter(Filter filter); private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter); private native int nativeDetachFilter(Filter filter);
@@ -106,18 +107,22 @@ public class DvrPlayback implements AutoCloseable {
/** @hide */ /** @hide */
public void setListener( public void setListener(
@NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) { @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) {
synchronized (mListenerLock) {
mExecutor = executor; mExecutor = executor;
mListener = listener; mListener = listener;
} }
}
private void onPlaybackStatusChanged(int status) { private void onPlaybackStatusChanged(int status) {
if (status == PLAYBACK_STATUS_EMPTY) { if (status == PLAYBACK_STATUS_EMPTY) {
mUnderflow++; mUnderflow++;
} }
synchronized (mListenerLock) {
if (mExecutor != null && mListener != null) { if (mExecutor != null && mListener != null) {
mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status)); mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
} }
} }
}
/** /**

View File

@@ -48,6 +48,7 @@ public class DvrRecorder implements AutoCloseable {
private int mSegmentId = 0; private int mSegmentId = 0;
private int mOverflow; private int mOverflow;
private Boolean mIsStopped = true; private Boolean mIsStopped = true;
private final Object mListenerLock = new Object();
private native int nativeAttachFilter(Filter filter); private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter); private native int nativeDetachFilter(Filter filter);
@@ -69,18 +70,22 @@ public class DvrRecorder implements AutoCloseable {
/** @hide */ /** @hide */
public void setListener( public void setListener(
@NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) { @NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) {
synchronized (mListenerLock) {
mExecutor = executor; mExecutor = executor;
mListener = listener; mListener = listener;
} }
}
private void onRecordStatusChanged(int status) { private void onRecordStatusChanged(int status) {
if (status == Filter.STATUS_OVERFLOW) { if (status == Filter.STATUS_OVERFLOW) {
mOverflow++; mOverflow++;
} }
synchronized (mListenerLock) {
if (mExecutor != null && mListener != null) { if (mExecutor != null && mListener != null) {
mExecutor.execute(() -> mListener.onRecordStatusChanged(status)); mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
} }
} }
}
/** /**

View File

@@ -227,6 +227,7 @@ public class Filter implements AutoCloseable {
private long mNativeContext; private long mNativeContext;
private FilterCallback mCallback; private FilterCallback mCallback;
private Executor mExecutor; private Executor mExecutor;
private final Object mCallbackLock = new Object();
private final long mId; private final long mId;
private int mMainType; private int mMainType;
private int mSubtype; private int mSubtype;
@@ -253,16 +254,20 @@ public class Filter implements AutoCloseable {
} }
private void onFilterStatus(int status) { private void onFilterStatus(int status) {
synchronized (mCallbackLock) {
if (mCallback != null && mExecutor != null) { if (mCallback != null && mExecutor != null) {
mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status)); mExecutor.execute(() -> mCallback.onFilterStatusChanged(this, status));
} }
} }
}
private void onFilterEvent(FilterEvent[] events) { private void onFilterEvent(FilterEvent[] events) {
synchronized (mCallbackLock) {
if (mCallback != null && mExecutor != null) { if (mCallback != null && mExecutor != null) {
mExecutor.execute(() -> mCallback.onFilterEvent(this, events)); mExecutor.execute(() -> mCallback.onFilterEvent(this, events));
} }
} }
}
/** @hide */ /** @hide */
public void setType(@Type int mainType, @Subtype int subtype) { public void setType(@Type int mainType, @Subtype int subtype) {
@@ -272,14 +277,18 @@ public class Filter implements AutoCloseable {
/** @hide */ /** @hide */
public void setCallback(FilterCallback cb, Executor executor) { public void setCallback(FilterCallback cb, Executor executor) {
synchronized (mCallbackLock) {
mCallback = cb; mCallback = cb;
mExecutor = executor; mExecutor = executor;
} }
}
/** @hide */ /** @hide */
public FilterCallback getCallback() { public FilterCallback getCallback() {
synchronized (mCallbackLock) {
return mCallback; return mCallback;
} }
}
/** /**
* Configures the filter. * Configures the filter.