Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de43e5f1 authored by Shai Barack's avatar Shai Barack
Browse files

Make writing Bitmap to ashmem faster

Write to memfd instead.
Avoid mmap+memcpy+munmap.

See b/407422742 for rationale, research, and benchmark results.

Bug: 407422742
Flag: com.android.graphics.hwui.flags.bitmap_use_memfd
Test: BitmapPerfTest
Change-Id: I64c6850721004f3f6ec71964169230f8c9828e16
parent d6941c1e
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -211,3 +211,11 @@ flag {
  description: "Whether to parcel implicit copies of bitmaps to ashmem as immutable"
  bug: "400807118"
}

flag {
  name: "bitmap_use_memfd"
  namespace: "system_performance"
  description: "Whether to parcel implicit copies of bitmaps to memfd instead of ashmem"
  bug: "400807118"
  is_fixed_read_only: true
}
 No newline at end of file
+42 −12
Original line number Diff line number Diff line
@@ -5,11 +5,15 @@
#ifdef __linux__
#include <com_android_graphics_hwui_flags.h>
#endif
#include <fcntl.h>
#include <hwui/Bitmap.h>
#include <hwui/Paint.h>
#include <inttypes.h>
#include <renderthread/RenderProxy.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <unistd.h>

#include <memory>

@@ -688,7 +692,31 @@ static binder_status_t writeBlob(AParcel* parcel, uint64_t bitmapId, const SkBit
        // Create new ashmem region with read/write priv
        auto ashmemId = Bitmap::getAshmemId("writeblob", bitmapId,
                                            bitmap.width(), bitmap.height(), size);
        base::unique_fd fd(ashmem_create_region(ashmemId.c_str(), size));
        base::unique_fd fd;

        if (com::android::graphics::hwui::flags::bitmap_use_memfd()) {
            fd.reset(syscall(__NR_memfd_create, ashmemId.c_str(), MFD_CLOEXEC | MFD_ALLOW_SEALING));
            if (fd.get() < 0) {
                return STATUS_NO_MEMORY;
            }

            ssize_t written = write(fd.get(), data, size);
            if (written != size) {
                return STATUS_NO_MEMORY;
            }

            if (fcntl(fd, F_ADD_SEALS,
                        // Disallow growing / shrinking
                        F_SEAL_GROW | F_SEAL_SHRINK
                        // If immutable, disallow writing
                        | (immutable ? F_SEAL_WRITE : 0)
                        // Seal the seals 🦭
                        | F_SEAL_SEAL) == -1) {
                return STATUS_UNKNOWN_ERROR;
            }

        } else {
            fd.reset(ashmem_create_region(ashmemId.c_str(), size));
            if (fd.get() < 0) {
                return STATUS_NO_MEMORY;
            }
@@ -705,6 +733,8 @@ static binder_status_t writeBlob(AParcel* parcel, uint64_t bitmapId, const SkBit
            if (immutable && ashmem_set_prot_region(fd.get(), PROT_READ) < 0) {
                return STATUS_UNKNOWN_ERROR;
            }
        }

        // Workaround b/149851140 in AParcel_writeParcelFileDescriptor
        int rawFd = fd.release();
        error = writeBlobFromFd(parcel, size, rawFd);