Перспективный анализ Android 13 systrace/perfetto Анализ исходного кода скриншота SurfaceFlinger

фон:

Создание скриншотов — функция, которая часто встречается в процессе разработки, но как эта функция реализована на нижнем уровне? Сегодня я поделюсь с вами принципом реализации скриншотов.
Сценарий создания снимка экрана:
Как правило, существует несколько способов сделать снимок экрана:
1. Клавиша уменьшения громкости + питание
2. Опустите строку состояния в systemui или выключите систему и выберите интерфейс
3. Режим командной строки оболочки adb Режим командной строки screencap

Основные из них перечислены выше. Хотя сценарии различаются, интерфейсы снимков экрана, которые они в конечном итоге вызывают, на самом деле одинаковы, и все они представляют собой методы снимков экрана, которые будут вызываться в Surfaceflinger. Ниже приводится анализ снимка экрана с использованием команды оболочки adb. строка, потому что это вызов интерфейса является самым простым.Этот метод анализа в основном использует метод анализа трассировки perfetto.

Исходный код, связанный с командой Screencap, и захват операции perfetto

Как получить перфетто:

1. Введите следующую команду, чтобы захватить перфетто

test@test:~$ aosp/external/perfetto/tools/record_android_trace -o $(date +%Y%m%d_%H%M%S)_trace_file.perfetto-trace -t 5s -b 32mb sched freq idle am wm gfx view binder_driver hal dalvik camera input res memory gfx view wm am ss video camera hal res sync idle binder_driver binder_lock ss

2. Введите следующую команду в другом терминале, чтобы сделать снимок экрана:

скриншот -p /sdcard/1.png

Местоположение кода:

рамки/база/cmds/screencap/screencap.cpp

int main(int argc, char** argv)
{
    
    
    std::optional<DisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
   //省略部分
    ProcessState::self()->setThreadPoolMaxThreadCount(0);
    ProcessState::self()->startThreadPool();

    sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
    //最为核心的方法ScreenshotClient::captureDisplay
    status_t result = ScreenshotClient::captureDisplay(*displayId, captureListener);
    if (result != NO_ERROR) {
    
    
        close(fd);
        return 1;
    }

    ScreenCaptureResults captureResults = captureListener->waitForResults();
    if (captureResults.result != NO_ERROR) {
    
    
        close(fd);
        return 1;
    }
    ui::Dataspace dataspace = captureResults.capturedDataspace;
    sp<GraphicBuffer> buffer = captureResults.buffer;

    result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);


    if (png) {
    
    
        AndroidBitmapInfo info;
        info.format = flinger2bitmapFormat(buffer->getPixelFormat());
        info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
        info.width = buffer->getWidth();
        info.height = buffer->getHeight();
        info.stride = buffer->getStride() * bytesPerPixel(buffer->getPixelFormat());

        int result = AndroidBitmap_compress(&info, static_cast<int32_t>(dataspace), base,
                                            ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100, &fd,
                                            [](void* fdPtr, const void* data, size_t size) -> bool {
    
    
                                                int bytesWritten = write(*static_cast<int*>(fdPtr),
                                                                         data, size);
                                                return bytesWritten == size;
                                            });
    
   //省略部分

        if (fn != NULL) {
    
    
            notifyMediaScanner(fn);
        }
    }
     
   //省略部分
    return 0;
}

Фактически, основной код всего скринкапа состоит всего из одного предложения:
ScreenshotClient::captureDisplay.
Это интерфейс, связанный с вызовом скриншотов. Интерфейс реализован следующим образом:

status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
                                          const sp<IScreenCaptureListener>& captureListener) {
    
    
    sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
    if (s == nullptr) return NO_INIT;

    binder::Status status = s->captureDisplay(captureArgs, captureListener);
    return status.transactionError();
}

По сути, суть заключается в кросс-процессном вызове и, наконец, будет вызван метод captureDisplay у Surfaceflinger:

status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
                                        const sp<IScreenCaptureListener>& captureListener) {
    
    
    ui::LayerStack layerStack;
    wp<const DisplayDevice> displayWeak;
    ui::Size size;
    ui::Dataspace dataspace;
    {
    
    
        Mutex::Autolock lock(mStateLock);

        const auto display = getDisplayDeviceLocked(displayId);
        if (!display) {
    
    
            return NAME_NOT_FOUND;
        }

        displayWeak = display;
        layerStack = display->getLayerStack();
        size = display->getLayerStackSpaceRect().getSize();

        dataspace =
                pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
    }

    RenderAreaFuture renderAreaFuture = ftl::defer([=] {
    
    
        return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace,
                                         false /* useIdentityTransform */,
                                         false /* captureSecureLayers */);
    });

    auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) {
    
    
        traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor);
    };


    auto future = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
                                      ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale,
                                      captureListener);
    return fenceStatus(future.get());
}
В сочетании с анализом следов

Конкретная система и совершенство вышеупомянутого процесса показаны следующим образом:
Вставьте сюда описание изображения
Здесь показано, что инициируется межпроцессный вызов, а целевым сегментом является процесс Surfaceflinger.Сводная
Вставьте сюда описание изображениядиаграмма трассировки выглядит следующим образом:

Вставьте сюда описание изображенияSurfaceflinger также имеет дополнительную клиентскую операцию обратного вызова:
Вставьте сюда описание изображения

1. Подготовьте буфер для рисования снимков экрана.
2. Доминируйте над Surfaceflinger и потребуйте предварительной обработки соответствующего слоя.
3. Используйте движок SkiaGl для рисования соответствующего слоя в новом буфере.
4. Уведомите клиента и перезвоните слушателю.

Чтобы получить более полезный видеоконтент с пошаговыми инструкциями по обучению, вы можете подписаться на публичную учетную запись или у владельца станции B (Qianlima Learning Framework)
https://blog.csdn.net/learnframework/article/details/132739059.
Вставьте сюда описание изображения

рекомендация

отblog.csdn.net/learnframework/article/details/133565273