安全播放:在 MediaCodec 中观察到崩溃
Secure Playback: Crash observed in MediaCodec
我正在努力在 Lollipop
上启用安全播放。我正在使用 ExoPlayer
来验证用例。我能够创建安全的 OMX
视频解码器组件 (H264.secure)。
但是,创建后,我在 MediaCodec
中遇到崩溃,如下所示
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xf0300000
eax f0300000 ebx ec1da038 ecx 00000005 edx 00000002
esi ec3ca200 edi f325b148
xcs 00000023 xds 0000002b xes 0000002b xfs 000000bf xss 0000002b
eip ec0e1655 ebp e05ffb28 esp e05ffa90 flags 00210202
#00 pc 000b5655 /system/lib/libstagefright.so (android::MediaCodec::onQueueInputBuffer(android::sp<android::AMessage> const&)+1061)
#01 pc 000b7b16 /system/lib/libstagefright.so (android::MediaCodec::onMessageReceived(android::sp<android::AMessage> const&)+1894)
#02 pc 0000e039 /system/lib/libstagefright_foundation.so (android::ALooperRoster::deliverMessage(android::sp<android::AMessage> const&)+345)
#03 pc 0000d3d0 /system/lib/libstagefright_foundation.so (android::ALooper::loop()+256)
#04 pc 0000d4ed /system/lib/libstagefright_foundation.so (android::ALooper::LooperThread::threadLoop()+29)
#05 pc 000169de /system/lib/libutils.so (android::Thread::_threadLoop(void*)+398)
#06 pc 0006fe92 /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+98)
#07 pc 000160fa /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+122)
经过一些分析,我发现崩溃发生在函数 ACodec::allocateBuffersOnPort
我是 android 的新手。任何调试它的指针都会有所帮助
总而言之,该问题特定于 设置 kFlagIsSecure
的情况 以及在不同进程中创建 OMX
缓冲区MediaCodec
,在 MediaCodec
中访问时会导致分段错误。有关此问题的详细背景,请参阅下文。
为了克服这个问题,我建议在 ACodec
中进行以下更改
size_t totalSize = def.nBufferCountActual * def.nBufferSize;
mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
/* Check if the component resides in same pid as ACodec */
bool isLocalComponent = mOMX->livesLocally(mNode, getpid()); // New Code
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
...
...
并修改分配检查如下
-- if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
-- || mUseMetadataOnEncoderOutput) {
// Modified check
++if (isLocalComponent && ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
++ || mUseMetadataOnEncoderOutput)) {
P.S: 我建议您向 Google 咨询此解决方案。
背景:
ExoPlayer
创建视频解码器作为 MediaCodec
组件。当一个新的MediaCodec
组件被创建时,这个过程中的corresponding object in JNI
is created. Please note that there is no interaction with MediaPlayerService
.
MediaCodec
在内部创建一个 ACodec
,它与 OMX
核心交互,随后与 OMX
组件交互。
ACodec
是在与 MediaCodec
相同的上下文中创建的。调用 OMXClient::connect
时,会在 MediaPlayer
服务的上下文中创建 OMX
句柄。因此,OMX
组件和 ACodec
的进程 ID 将不同。
对于安全输入缓冲区,there is a special handling in ACodec::allocateBuffersOnPorts
。在这里,从 allocateBuffer 返回的缓冲区指针被包装为 ABuffer
并排队等待使用。在我看来,当前的实现中存在如下潜在问题。
ACodec::allocateBufferOnPort
呼叫 mOMX->allocateBuffer
。 mOMX
属于 IOMX
类型,即涉及活页夹交互。请注意此变量 &buffer_data
,它将在 ACodec::allocateBufferOnPorts
层中转换为 ptr
,因为这对以下部分至关重要。
在实际运行在MediaPlayerService
上下文中的OMXNodeInstance
中,调用了传统的OMX_AllocateBuffer
。在 OMXNodeInstance::allocateBuffer
中,分配后 *buffer_data
被 header->pBuffer
初始化,这基本上是 OMX
组件可能通过简单的 malloc
调用分配的本地指针。
当控件returns时,相同的指针被写入binder接口here and subsequently read back here。所以,控件出来的时候mOMX->allocateBuffer
,ptr
的值相当于OMX
组件分配的header->pBuffer
,但是两者是在2个不同的进程中。
因此,当 ACodec
基于此 ptr
创建 ABuffer
然后在 MediaCodec
中访问时,将在创建地址时发生访问冲突与 MediaCodec
的进程 ID 相比,在不同的进程上下文中。
我正在努力在 Lollipop
上启用安全播放。我正在使用 ExoPlayer
来验证用例。我能够创建安全的 OMX
视频解码器组件 (H264.secure)。
但是,创建后,我在 MediaCodec
中遇到崩溃,如下所示
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xf0300000
eax f0300000 ebx ec1da038 ecx 00000005 edx 00000002
esi ec3ca200 edi f325b148
xcs 00000023 xds 0000002b xes 0000002b xfs 000000bf xss 0000002b
eip ec0e1655 ebp e05ffb28 esp e05ffa90 flags 00210202
#00 pc 000b5655 /system/lib/libstagefright.so (android::MediaCodec::onQueueInputBuffer(android::sp<android::AMessage> const&)+1061)
#01 pc 000b7b16 /system/lib/libstagefright.so (android::MediaCodec::onMessageReceived(android::sp<android::AMessage> const&)+1894)
#02 pc 0000e039 /system/lib/libstagefright_foundation.so (android::ALooperRoster::deliverMessage(android::sp<android::AMessage> const&)+345)
#03 pc 0000d3d0 /system/lib/libstagefright_foundation.so (android::ALooper::loop()+256)
#04 pc 0000d4ed /system/lib/libstagefright_foundation.so (android::ALooper::LooperThread::threadLoop()+29)
#05 pc 000169de /system/lib/libutils.so (android::Thread::_threadLoop(void*)+398)
#06 pc 0006fe92 /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+98)
#07 pc 000160fa /system/lib/libutils.so (thread_data_t::trampoline(thread_data_t const*)+122)
经过一些分析,我发现崩溃发生在函数 ACodec::allocateBuffersOnPort
我是 android 的新手。任何调试它的指针都会有所帮助
总而言之,该问题特定于 设置 kFlagIsSecure
的情况 以及在不同进程中创建 OMX
缓冲区MediaCodec
,在 MediaCodec
中访问时会导致分段错误。有关此问题的详细背景,请参阅下文。
为了克服这个问题,我建议在 ACodec
size_t totalSize = def.nBufferCountActual * def.nBufferSize;
mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
/* Check if the component resides in same pid as ACodec */
bool isLocalComponent = mOMX->livesLocally(mNode, getpid()); // New Code
for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {
sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);
...
...
并修改分配检查如下
-- if ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
-- || mUseMetadataOnEncoderOutput) {
// Modified check
++if (isLocalComponent && ((portIndex == kPortIndexInput && (mFlags & kFlagIsSecure))
++ || mUseMetadataOnEncoderOutput)) {
P.S: 我建议您向 Google 咨询此解决方案。
背景:
ExoPlayer
创建视频解码器作为 MediaCodec
组件。当一个新的MediaCodec
组件被创建时,这个过程中的corresponding object in JNI
is created. Please note that there is no interaction with MediaPlayerService
.
MediaCodec
在内部创建一个 ACodec
,它与 OMX
核心交互,随后与 OMX
组件交互。
ACodec
是在与 MediaCodec
相同的上下文中创建的。调用 OMXClient::connect
时,会在 MediaPlayer
服务的上下文中创建 OMX
句柄。因此,OMX
组件和 ACodec
的进程 ID 将不同。
对于安全输入缓冲区,there is a special handling in ACodec::allocateBuffersOnPorts
。在这里,从 allocateBuffer 返回的缓冲区指针被包装为 ABuffer
并排队等待使用。在我看来,当前的实现中存在如下潜在问题。
ACodec::allocateBufferOnPort
呼叫 mOMX->allocateBuffer
。 mOMX
属于 IOMX
类型,即涉及活页夹交互。请注意此变量 &buffer_data
,它将在 ACodec::allocateBufferOnPorts
层中转换为 ptr
,因为这对以下部分至关重要。
在实际运行在MediaPlayerService
上下文中的OMXNodeInstance
中,调用了传统的OMX_AllocateBuffer
。在 OMXNodeInstance::allocateBuffer
中,分配后 *buffer_data
被 header->pBuffer
初始化,这基本上是 OMX
组件可能通过简单的 malloc
调用分配的本地指针。
当控件returns时,相同的指针被写入binder接口here and subsequently read back here。所以,控件出来的时候mOMX->allocateBuffer
,ptr
的值相当于OMX
组件分配的header->pBuffer
,但是两者是在2个不同的进程中。
因此,当 ACodec
基于此 ptr
创建 ABuffer
然后在 MediaCodec
中访问时,将在创建地址时发生访问冲突与 MediaCodec
的进程 ID 相比,在不同的进程上下文中。