diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 31d759ea92e6262d8d38456d456dde217f357938..18080e4478fc9bc289c52bc5acbff1018bf9d237 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -286,6 +286,16 @@ public abstract class DisplayEventReceiver { long renderPeriod) { } + /** + * Called when a display hdcp levels change event is received. + * + * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. + * @param connectedLevel the new connected HDCP level + * @param maxLevel the maximum HDCP level + */ + public void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel) { + } + /** * Represents a mapping between a UID and an override frame rate */ @@ -374,4 +384,11 @@ public abstract class DisplayEventReceiver { onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); } + // Called from native code. + @SuppressWarnings("unused") + private void dispatchHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, + int maxLevel) { + onHdcpLevelsChanged(physicalDisplayId, connectedLevel, maxLevel); + } + } diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index fef8ad7499f7ac8856da112e664201e1e2b53c79..f007cc5a23bd1cfbd8a4c011b4f980b73d5ac60d 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -41,6 +41,7 @@ static struct { jmethodID dispatchHotplugConnectionError; jmethodID dispatchModeChanged; jmethodID dispatchFrameRateOverrides; + jmethodID dispatchHdcpLevelsChanged; struct { jclass clazz; @@ -96,6 +97,8 @@ private: void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) override; void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {} + void dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, int connectedLevel, + int maxLevel) override; }; NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, @@ -294,6 +297,22 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides( mMessageQueue->raiseAndClearException(env, "dispatchModeChanged"); } +void NativeDisplayEventReceiver::dispatchHdcpLevelsChanged(PhysicalDisplayId displayId, + int connectedLevel, int maxLevel) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + + ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); + if (receiverObj.get()) { + ALOGV("receiver %p ~ Invoking hdcp levels changed handler.", this); + env->CallVoidMethod(receiverObj.get(), + gDisplayEventReceiverClassInfo.dispatchHdcpLevelsChanged, + displayId.value, connectedLevel, maxLevel); + ALOGV("receiver %p ~ Returned from hdcp levels changed handler.", this); + } + + mMessageQueue->raiseAndClearException(env, "dispatchHdcpLevelsChanged"); +} + static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak, jobject messageQueueObj, jint vsyncSource, jint eventRegistration, jlong layerHandle) { @@ -385,6 +404,9 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchFrameRateOverrides", "(JJ[Landroid/view/DisplayEventReceiver$FrameRateOverride;)V"); + gDisplayEventReceiverClassInfo.dispatchHdcpLevelsChanged = + GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchHdcpLevelsChanged", + "(JII)V"); jclass frameRateOverrideClazz = FindClassOrDie(env, "android/view/DisplayEventReceiver$FrameRateOverride"); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 22898a65c5defe0179e6efd45892dc6ea0d0478d..25576ce9efd6174a022059cbcb5c4497eaff9c06 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.res.Resources; import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession; import android.hardware.sidekick.SidekickInternal; +import android.media.MediaDrm; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -242,6 +243,10 @@ final class LocalDisplayAdapter extends DisplayAdapter { private SurfaceControl.DisplayMode mActiveSfDisplayMode; // The active display vsync period in SurfaceFlinger private float mActiveRenderFrameRate; + // The current HDCP level supported by the display, 0 indicates unset + // values are defined in hardware/interfaces/drm/aidl/android/hardware/drm/HdcpLevel.aidl + private int mConnectedHdcpLevel; + private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides = new DisplayEventReceiver.FrameRateOverride[0]; @@ -675,8 +680,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.yDpi = mActiveSfDisplayMode.yDpi; mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo; - // Assume that all built-in displays that have secure output (eg. HDCP) also - // support compositing from gralloc protected buffers. + if (mConnectedHdcpLevel != 0) { + mStaticDisplayInfo.secure = mConnectedHdcpLevel >= MediaDrm.HDCP_V1; + } if (mStaticDisplayInfo.secure) { mInfo.flags = DisplayDeviceInfo.FLAG_SECURE | DisplayDeviceInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS; @@ -1093,6 +1099,12 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } + public void onHdcpLevelsChangedLocked(int connectedLevel, int maxLevel) { + if (updateHdcpLevelsLocked(connectedLevel, maxLevel)) { + updateDeviceInfoLocked(); + } + } + public boolean updateActiveModeLocked(int activeSfModeId, float renderFrameRate) { if (mActiveSfDisplayMode.id == activeSfModeId && mActiveRenderFrameRate == renderFrameRate) { @@ -1118,6 +1130,22 @@ final class LocalDisplayAdapter extends DisplayAdapter { return true; } + public boolean updateHdcpLevelsLocked(int connectedLevel, int maxLevel) { + if (connectedLevel > maxLevel) { + Slog.w(TAG, "HDCP connected level: " + connectedLevel + + " is larger than max level: " + maxLevel + + ", ignoring request."); + return false; + } + + if (mConnectedHdcpLevel == connectedLevel) { + return false; + } + + mConnectedHdcpLevel = connectedLevel; + return true; + } + public void requestColorModeLocked(int colorMode) { if (mActiveColorMode == colorMode) { return; @@ -1387,6 +1415,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { long renderPeriod); void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, DisplayEventReceiver.FrameRateOverride[] overrides); + void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel); } @@ -1420,6 +1449,11 @@ final class LocalDisplayAdapter extends DisplayAdapter { DisplayEventReceiver.FrameRateOverride[] overrides) { mListener.onFrameRateOverridesChanged(timestampNanos, physicalDisplayId, overrides); } + + @Override + public void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel) { + mListener.onHdcpLevelsChanged(physicalDisplayId, connectedLevel, maxLevel); + } } private final class LocalDisplayEventListener implements DisplayEventListener { @@ -1489,6 +1523,26 @@ final class LocalDisplayAdapter extends DisplayAdapter { device.onFrameRateOverridesChanged(overrides); } } + + @Override + public void onHdcpLevelsChanged(long physicalDisplayId, int connectedLevel, int maxLevel) { + if (DEBUG) { + Slog.d(TAG, "onHdcpLevelsChanged(physicalDisplayId=" + physicalDisplayId + + ", connectedLevel=" + connectedLevel + ", maxLevel=" + maxLevel + ")"); + } + synchronized (getSyncRoot()) { + LocalDisplayDevice device = mDevices.get(physicalDisplayId); + if (device == null) { + if (DEBUG) { + Slog.d(TAG, "Received hdcp levels change for unhandled physical display: " + + "physicalDisplayId=" + physicalDisplayId); + } + return; + } + + device.onHdcpLevelsChangedLocked(connectedLevel, maxLevel); + } + } } @VisibleForTesting