抚州市网站建设_网站建设公司_轮播图_seo优化
2026/1/22 10:23:33 网站建设 项目流程

App_Deadline_Missed_Deep_Dive - 副本

Android Graphics Deadline & Fence Mechanism Deep Dive

This document details the logic behind "App Deadline Missed" in Android's FrameTimeline, tracing the mActuals.endTime from SurfaceFlinger down to the Linux Kernel Fence mechanism.

1. Jank Classification: App Deadline Missed

The core logic for defining a frame as "Jank" due to the application missing its deadline resides in [FrameTimeline.cpp](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp).

File: [frameworks/native/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp)
Function: SurfaceFrame::classifyJankLocked

void SurfaceFrame::classifyJankLocked(...) {// 1. Calculate the delay: Actual End Time - Predicted End TimedeadlineDelta = mActuals.endTime - mPredictions.endTime;// ...// 2. Determine if the frame finished lateif (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {mFrameReadyMetadata = FrameReadyMetadata::LateFinish;} else {mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;}// ...// 3. Assign Jank Typeif (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {// Finish late, Present late -> The App took too long!mJankType |= JankType::AppDeadlineMissed;}
}
  • Logic: If mActuals.endTime (when App finished) is significantly later than mPredictions.endTime (when system expected it to finish), it's flagged as AppDeadlineMissed.

2. Tracking mActuals.endTime

The mActuals.endTime is not just a timestamp recorded when a function returns; it represents the physical completion time of the GPU work for that frame.

2.1 Assignment in FrameTimeline

File: [frameworks/native/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp)

void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) {std::scoped_lock lock(mMutex);// The end time is the MAX of when the buffer was queued and when the fence signaled.// Usually, acquireFenceTime (GPU finish) is the limiting factor.mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime);
}

2.2 Integration in Layer (SurfaceFlinger)

File: [frameworks/native/services/surfaceflinger/Layer.cpp](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp)

The connection happens during [updateTexImage](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp#3400-3449) (when SF latches a new buffer).

void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) {// ...// 1. Get the fence associated with the buffer submitted by the Appconst auto acquireFence = std::make_shared<FenceTime>(mDrawingState.acquireFence);// ...if (bufferSurfaceFrame != nullptr ...) {// 2. Pass the SIGNAL TIME of the fence to FrameTimeline// *CRITICAL*: mDrawingState.acquireFenceTime->getSignalTime() retrieves the GPU timestampaddSurfaceFramePresentedForBuffer(bufferSurfaceFrame,mDrawingState.acquireFenceTime->getSignalTime(),latchTime);}
}

Key Difference:

  • [updateTexImage](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp#3400-3449): The "Worker". Executes the logic to latch the buffer and update layer state.
  • [addSurfaceFramePresentedForBuffer](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp#1392-1400): The "Bookkeeper". Reports the successful latch and the timing data (derived from [updateTexImage](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp#3400-3449)) to FrameTimeline for analysis.

3. The Fence Mechanism: Acquire & Release

Synchronization between the App (Producer) and SurfaceFlinger (Consumer) relies on Fences, which act as "Traffic Lights" for shared memory (DMA Buffers).

Type Direction Meaning
AcquireFence App -> SF "I'm done drawing." SF waits for this before compositing. Its signal time = mActuals.endTime.
ReleaseFence SF -> App "I'm done using it." App waits for this before writing the next frame into this buffer.

Workflow:

  1. App: Draws frame -> queueBuffer (attaches [AcquireFence](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp#335-339) "Red Light").
  2. GPU: Continues rendering in background.
  3. SF: [updateTexImage](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp#3400-3449) -> Receives Buffer + Fence.
  4. Hardware: GPU finishes rendering -> Interrupt triggers.
  5. Kernel: Sets Fence to "Green Light" (Signaled) & records Timestamp.
  6. SF: Reads Timestamp -> mActuals.endTime.

4. Kernel Implementation Details

The timestamp used for mActuals.endTime originates deep within the Linux Kernel.

4.1 Kernel: Reading the Timestamp

File: drivers/dma-buf/sync_file.c (Linux Kernel)

When SurfaceFlinger calls fence->getSignalTime(), it eventually invokes an ioctl that hits this kernel function:

static int sync_fill_fence_info(struct dma_fence *fence,struct sync_fence_info *info)
{// ...info->status = dma_fence_get_status(fence);// Core Logic:// If signaled via dma_fence_is_signaled(), read the timestamp.// ktime_to_ns calls dma_fence_timestamp() internally or accesses the field directly.info->timestamp_ns =dma_fence_is_signaled(fence) ?ktime_to_ns(dma_fence_timestamp(fence)) :ktime_set(0, 0);return info->status;
}

4.2 Kernel: Safe Timestamp Access

File: include/linux/dma-fence.h

The accessor is careful about currency to avoid race conditions:

static inline ktime_t dma_fence_timestamp(struct dma_fence *fence)
{// Safety check: Don't read if not signaledif (WARN_ON(!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)))return ktime_get();// Spin-wait until the timestamp is actually writtenwhile (!test_bit(DMA_FENCE_FLAG_TIMESTAMP_BIT, &fence->flags))cpu_relax(); // Wait for the other CPU to finish writingreturn fence->timestamp;
}

4.3 Kernel: Signaling Completion (DRM Scheduler)

File: drivers/gpu/drm/scheduler/sched_main.c

Where is the timestamp set? In the GPU Scheduler, when a job completes:

static void drm_sched_job_done(struct drm_sched_job *s_job)
{struct drm_sched_fence *s_fence = s_job->s_fence;// ...// *CRITICAL*: This function marks the fence as signaled and typically traces the timestamp.drm_sched_fence_finished(s_fence); // ...wake_up_interruptible(&sched->wake_up_worker);
}

5. Architectural Why: Fence in DMA Path?

Why is [fence](file:///mnt/fileroot/xxxx/board/frameworks/native/services/surfaceflinger/Layer.cpp#3348-3362) code found in drivers/dma-buf or similar DMA paths?

  • Co-existence with DMA-BUF: Fences are the synchronization primitive for Zero-Copy Buffer Sharing (DMA-BUF).
  • Buffer Sharing Protocol: If Device A (GPU) shares memory with Device B (Display) via DMA, they need a vendor-agnostic way to say "I'm done". dma-fence is that standard.
  • Not just for GPU: It serves Camera, Video Encoders, NPUs, etc. It manages access to DMA Memory Resources, hence its location in the kernel source tree.

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询