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

Commit 6f265c72 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 9489393 from 808ff1d4 to udc-release

Change-Id: Iaaec11216bf07445cf498a517b91946bd938c921
parents 46969a54 808ff1d4
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -12,3 +12,6 @@ IndentWidth: 4
PenaltyBreakBeforeFirstCallParameter: 100000
SpacesBeforeTrailingComments: 1
IncludeBlocks: Preserve

DerivePointerAlignment: false
PointerAlignment: Left
+26 −1
Original line number Diff line number Diff line
@@ -778,6 +778,9 @@ enum {
     *   proportion of the touch pad's size. For example, if a touch pad is 1000 units wide, and a
     *   swipe gesture starts at X = 500 then moves to X = 400, this axis would have a value of
     *   -0.1.
     *
     * These values are relative to the state from the last event, not accumulated, so developers
     * should make sure to process this axis value for all batched historical events.
     */
    AMOTION_EVENT_AXIS_GESTURE_X_OFFSET = 48,
    /**
@@ -791,6 +794,9 @@ enum {
     *
     * - For a touch pad, reports the distance that should be scrolled in the X axis as a result of
     *   the user's two-finger scroll gesture, in display pixels.
     *
     * These values are relative to the state from the last event, not accumulated, so developers
     * should make sure to process this axis value for all batched historical events.
     */
    AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE = 50,
    /**
@@ -799,6 +805,18 @@ enum {
     * The same as {@link AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE}, but for the Y axis.
     */
    AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE = 51,
    /**
     * Axis constant: pinch scale factor of a motion event.
     *
     * - For a touch pad, reports the change in distance between the fingers when the user is making
     *   a pinch gesture, as a proportion of that distance when the gesture was last reported. For
     *   example, if the fingers were 50 units apart and are now 52 units apart, the scale factor
     *   would be 1.04.
     *
     * These values are relative to the state from the last event, not accumulated, so developers
     * should make sure to process this axis value for all batched historical events.
     */
    AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR = 52,

    /**
     * Note: This is not an "Axis constant". It does not represent any axis, nor should it be used
@@ -806,7 +824,7 @@ enum {
     * to make some computations (like iterating through all possible axes) cleaner.
     * Please update the value accordingly if you add a new axis.
     */
    AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE,
    AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE = AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR,

    // NOTE: If you add a new axis here you must also add it to several other files.
    //       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
@@ -891,6 +909,13 @@ enum AMotionClassification : uint32_t {
     * why they have a separate constant from two-finger swipes.
     */
    AMOTION_EVENT_CLASSIFICATION_MULTI_FINGER_SWIPE = 4,
    /**
     * Classification constant: pinch.
     *
     * The current event stream represents the user pinching with two fingers on a touchpad. The
     * gesture is centered around the current cursor position.
     */
    AMOTION_EVENT_CLASSIFICATION_PINCH = 5,
};

/**
+5 −0
Original line number Diff line number Diff line
@@ -308,6 +308,11 @@ enum class MotionClassification : uint8_t {
     * have a separate constant from two-finger swipes.
     */
    MULTI_FINGER_SWIPE = AMOTION_EVENT_CLASSIFICATION_MULTI_FINGER_SWIPE,
    /**
     * The current gesture represents the user pinching with two fingers on a touchpad. The gesture
     * is centered around the current cursor position.
     */
    PINCH = AMOTION_EVENT_CLASSIFICATION_PINCH,
};

/**
+3 −0
Original line number Diff line number Diff line
@@ -87,6 +87,9 @@ public:
    /* Combines this key character map with the provided overlay. */
    void combine(const KeyCharacterMap& overlay);

    /* Clears already applied layout overlay */
    void clearLayoutOverlay();

    /* Gets the keyboard type. */
    KeyboardType getKeyboardType() const;

+133 −110
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/BinderRecordReplay.h>
#include <sys/mman.h>
#include <algorithm>

using android::Parcel;
@@ -42,34 +43,38 @@ static_assert(PADDING8(8) == 0);
//
// A RecordedTransaction is written to a file as a sequence of Chunks.
//
// A Chunk consists of a ChunkDescriptor, Data, and Padding.
// A Chunk consists of a ChunkDescriptor, Data, Padding, and a Checksum.
//
// Data and Padding may each be zero-length as specified by the
// ChunkDescriptor.
// The ChunkDescriptor identifies the type of Data in the chunk, and the size
// of the Data.
//
// The ChunkDescriptor identifies the type of data in the chunk, the size of
// the data in bytes, and the number of zero-bytes padding to land on an
// 8-byte boundary by the end of the Chunk.
// The Data may be any uint32 number of bytes in length in [0-0xfffffff0].
//
// Padding is between [0-7] zero-bytes after the Data such that the Chunk ends
// on an 8-byte boundary. The ChunkDescriptor's dataSize does not include the
// size of Padding.
//
// The checksum is a 64-bit wide XOR of all previous data from the start of the
// ChunkDescriptor to the end of Padding.
//
// ┌───────────────────────────┐
// │Chunk                      │
// │┌────────────────────────┐│
// │┌────────────────────────┐ 
// ││ChunkDescriptor         │ │
// ││┌───────────┬───────────┐││
// │││chunkType  │paddingSize│││
// │││uint32_t   │uint32_t   ├┼┼───┐
// ││├───────────┴───────────┤││   │
// │││dataSize               │││   │
// │││uint64_t               ├┼┼─┐ │
// ││└───────────────────────┘││ │ │
// │└─────────────────────────┘│ │ │
// │┌─────────────────────────┐│ │ │
// ││Data                     ││ │ │
// ││bytes * dataSize         │◀─┘ │
// │└─────────────────────────┘│   │
// ││┌───────────┬──────────┐│ │
// │││chunkType  │dataSize  ├┼─┼─┐
// │││uint32_t   │uint32_t  ││ │ │
// ││└───────────┴──────────┘│ │ │
// │└────────────────────────┘ │ │
// │┌─────────────────────────┐│ │
// ││Padding                  ││   │
// ││bytes * paddingSize      │◀───┘
// ││Data                     ││ │
// ││bytes * dataSize         │◀─┘
// ││   ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤│
// ││           Padding       ││
// │└───┴─────────────────────┘│
// │┌─────────────────────────┐│
// ││checksum                 ││
// ││uint64_t                 ││
// │└─────────────────────────┘│
// └───────────────────────────┘
//
@@ -85,20 +90,20 @@ static_assert(PADDING8(8) == 0);
// ║      End Chunk       ║
// ╚══════════════════════╝
//
// On reading a RecordedTransaction, an unrecognized chunk is skipped using
// the size information in the ChunkDescriptor. Chunks are read and either
// assimilated or skipped until an End Chunk is encountered. This has three
// notable implications:
// On reading a RecordedTransaction, an unrecognized chunk is checksummed
// then skipped according to size information in the ChunkDescriptor. Chunks
// are read and either assimilated or skipped until an End Chunk is
// encountered. This has three notable implications:
//
// 1. Older and newer implementations should be able to read one another's
//    Transactions, though there will be loss of information.
// 2. With the exception of the End Chunk, Chunks can appear in any
//    order and even repeat, though this is not recommended.
// 2. With the exception of the End Chunk, Chunks can appear in any order
//    and even repeat, though this is not recommended.
// 3. If any Chunk is repeated, old values will be overwritten by versions
//    encountered later in the file.
//
// No effort is made to ensure the expected chunks are present. A single
// End Chunk may therefore produce a empty, meaningless RecordedTransaction.
// End Chunk may therefore produce an empty, meaningless RecordedTransaction.

RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept {
    mHeader = t.mHeader;
@@ -121,12 +126,12 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t cod
                 0};

    if (t.mSent.setData(dataParcel.data(), dataParcel.dataSize()) != android::NO_ERROR) {
        LOG(INFO) << "Failed to set sent parcel data.";
        LOG(ERROR) << "Failed to set sent parcel data.";
        return std::nullopt;
    }

    if (t.mReply.setData(replyParcel.data(), replyParcel.dataSize()) != android::NO_ERROR) {
        LOG(INFO) << "Failed to set reply parcel data.";
        LOG(ERROR) << "Failed to set reply parcel data.";
        return std::nullopt;
    }

@@ -134,94 +139,111 @@ std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t cod
}

enum {
    HEADER_CHUNK = 0x00000001,
    DATA_PARCEL_CHUNK = 0x00000002,
    REPLY_PARCEL_CHUNK = 0x00000003,
    INVALID_CHUNK = 0x00fffffe,
    HEADER_CHUNK = 1,
    DATA_PARCEL_CHUNK = 2,
    REPLY_PARCEL_CHUNK = 3,
    END_CHUNK = 0x00ffffff,
};

struct ChunkDescriptor {
    uint32_t chunkType = 0;
    uint32_t padding = 0;
    uint32_t dataSize = 0;
    uint32_t reserved = 0; // Future checksum
};
static_assert(sizeof(ChunkDescriptor) % 8 == 0);

constexpr uint32_t kMaxChunkDataSize = 0xfffffff0;
typedef uint64_t transaction_checksum_t;

static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut) {
static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut,
                                             transaction_checksum_t* sum) {
    if (!android::base::ReadFully(fd, chunkOut, sizeof(ChunkDescriptor))) {
        LOG(INFO) << "Failed to read Chunk Descriptor from fd " << fd.get();
        LOG(ERROR) << "Failed to read Chunk Descriptor from fd " << fd.get();
        return android::UNKNOWN_ERROR;
    }
    if (PADDING8(chunkOut->dataSize) != chunkOut->padding) {
        chunkOut->chunkType = INVALID_CHUNK;
        LOG(INFO) << "Chunk data and padding sizes do not align." << fd.get();
        return android::BAD_VALUE;
    }

    *sum ^= *reinterpret_cast<transaction_checksum_t*>(chunkOut);
    return android::NO_ERROR;
}

std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) {
    RecordedTransaction t;
    ChunkDescriptor chunk;

    const long pageSize = sysconf(_SC_PAGE_SIZE);
    do {
        if (NO_ERROR != readChunkDescriptor(fd, &chunk)) {
            LOG(INFO) << "Failed to read chunk descriptor.";
        transaction_checksum_t checksum = 0;
        if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) {
            LOG(ERROR) << "Failed to read chunk descriptor.";
            return std::nullopt;
        }
        off_t fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR);
        off_t mmapPageAlignedStart = (fdCurrentPosition / pageSize) * pageSize;
        off_t mmapPayloadStartOffset = fdCurrentPosition - mmapPageAlignedStart;

        if (chunk.dataSize > kMaxChunkDataSize) {
            LOG(ERROR) << "Chunk data exceeds maximum size.";
            return std::nullopt;
        }

        size_t chunkPayloadSize =
                chunk.dataSize + PADDING8(chunk.dataSize) + sizeof(transaction_checksum_t);

        if (PADDING8(chunkPayloadSize) != 0) {
            LOG(ERROR) << "Invalid chunk size, not aligned " << chunkPayloadSize;
            return std::nullopt;
        }

        transaction_checksum_t* payloadMap = reinterpret_cast<transaction_checksum_t*>(
                mmap(NULL, chunkPayloadSize + mmapPayloadStartOffset, PROT_READ, MAP_SHARED,
                     fd.get(), mmapPageAlignedStart));
        payloadMap += mmapPayloadStartOffset /
                sizeof(transaction_checksum_t); // Skip chunk descriptor and required mmap
                                                // page-alignment
        if (payloadMap == MAP_FAILED) {
            LOG(ERROR) << "Memory mapping failed for fd " << fd.get() << ": " << errno << " "
                       << strerror(errno);
            return std::nullopt;
        }
        for (size_t checksumIndex = 0;
             checksumIndex < chunkPayloadSize / sizeof(transaction_checksum_t); checksumIndex++) {
            checksum ^= payloadMap[checksumIndex];
        }
        if (checksum != 0) {
            LOG(ERROR) << "Checksum failed.";
            return std::nullopt;
        }
        lseek(fd.get(), chunkPayloadSize, SEEK_CUR);

        switch (chunk.chunkType) {
            case HEADER_CHUNK: {
                if (chunk.dataSize != static_cast<uint32_t>(sizeof(TransactionHeader))) {
                    LOG(INFO) << "Header Chunk indicated size " << chunk.dataSize << "; Expected "
                    LOG(ERROR) << "Header Chunk indicated size " << chunk.dataSize << "; Expected "
                               << sizeof(TransactionHeader) << ".";
                    return std::nullopt;
                }
                if (!android::base::ReadFully(fd, &t.mHeader, chunk.dataSize)) {
                    LOG(INFO) << "Failed to read transactionHeader from fd " << fd.get();
                    return std::nullopt;
                }
                lseek(fd.get(), chunk.padding, SEEK_CUR);
                t.mHeader = *reinterpret_cast<TransactionHeader*>(payloadMap);
                break;
            }
            case DATA_PARCEL_CHUNK: {
                std::vector<uint8_t> bytes;
                bytes.resize(chunk.dataSize);
                if (!android::base::ReadFully(fd, bytes.data(), chunk.dataSize)) {
                    LOG(INFO) << "Failed to read sent parcel data from fd " << fd.get();
                if (t.mSent.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                                    chunk.dataSize) != android::NO_ERROR) {
                    LOG(ERROR) << "Failed to set sent parcel data.";
                    return std::nullopt;
                }
                if (t.mSent.setData(bytes.data(), chunk.dataSize) != android::NO_ERROR) {
                    LOG(INFO) << "Failed to set sent parcel data.";
                    return std::nullopt;
                }
                lseek(fd.get(), chunk.padding, SEEK_CUR);
                break;
            }
            case REPLY_PARCEL_CHUNK: {
                std::vector<uint8_t> bytes;
                bytes.resize(chunk.dataSize);
                if (!android::base::ReadFully(fd, bytes.data(), chunk.dataSize)) {
                    LOG(INFO) << "Failed to read reply parcel data from fd " << fd.get();
                if (t.mReply.setData(reinterpret_cast<const unsigned char*>(payloadMap),
                                     chunk.dataSize) != android::NO_ERROR) {
                    LOG(ERROR) << "Failed to set reply parcel data.";
                    return std::nullopt;
                }
                if (t.mReply.setData(bytes.data(), chunk.dataSize) != android::NO_ERROR) {
                    LOG(INFO) << "Failed to set reply parcel data.";
                    return std::nullopt;
                }
                lseek(fd.get(), chunk.padding, SEEK_CUR);
                break;
            }
            case INVALID_CHUNK:
                LOG(INFO) << "Invalid chunk.";
                return std::nullopt;
            case END_CHUNK:
                LOG(INFO) << "Read end chunk";
                FALLTHROUGH_INTENDED;
            default:
                // Unrecognized or skippable chunk
                lseek(fd.get(), chunk.dataSize + chunk.padding, SEEK_CUR);
                break;
            default:
                LOG(INFO) << "Unrecognized chunk.";
                continue;
        }
    } while (chunk.chunkType != END_CHUNK);

@@ -230,36 +252,37 @@ std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd

android::status_t RecordedTransaction::writeChunk(borrowed_fd fd, uint32_t chunkType,
                                                  size_t byteCount, const uint8_t* data) const {
    // Write Chunk Descriptor
    // - Chunk Type
    if (!android::base::WriteFully(fd, &chunkType, sizeof(uint32_t))) {
        LOG(INFO) << "Failed to write chunk header to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    // - Chunk Data Padding Size
    uint32_t additionalPaddingCount = static_cast<uint32_t>(PADDING8(byteCount));
    if (!android::base::WriteFully(fd, &additionalPaddingCount, sizeof(uint32_t))) {
        LOG(INFO) << "Failed to write chunk padding size to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    // - Chunk Data Size
    uint64_t byteCountToWrite = (uint64_t)byteCount;
    if (!android::base::WriteFully(fd, &byteCountToWrite, sizeof(uint64_t))) {
        LOG(INFO) << "Failed to write chunk size to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    if (byteCount == 0) {
        return NO_ERROR;
    }
    if (byteCount > kMaxChunkDataSize) {
        LOG(ERROR) << "Chunk data exceeds maximum size";
        return BAD_VALUE;
    }
    ChunkDescriptor descriptor = {.chunkType = chunkType,
                                  .dataSize = static_cast<uint32_t>(byteCount)};
    // Prepare Chunk content as byte *
    const std::byte* descriptorBytes = reinterpret_cast<const std::byte*>(&descriptor);
    const std::byte* dataBytes = reinterpret_cast<const std::byte*>(data);

    if (!android::base::WriteFully(fd, data, byteCount)) {
        LOG(INFO) << "Failed to write chunk data to fd " << fd.get();
        return UNKNOWN_ERROR;
    // Add Chunk to intermediate buffer, except checksum
    std::vector<std::byte> buffer;
    buffer.insert(buffer.end(), descriptorBytes, descriptorBytes + sizeof(ChunkDescriptor));
    buffer.insert(buffer.end(), dataBytes, dataBytes + byteCount);
    std::byte zero{0};
    buffer.insert(buffer.end(), PADDING8(byteCount), zero);

    // Calculate checksum from buffer
    transaction_checksum_t* checksumData = reinterpret_cast<transaction_checksum_t*>(buffer.data());
    transaction_checksum_t checksumValue = 0;
    for (size_t idx = 0; idx < (buffer.size() / sizeof(transaction_checksum_t)); idx++) {
        checksumValue ^= checksumData[idx];
    }

    const uint8_t zeros[7] = {0};
    if (!android::base::WriteFully(fd, zeros, additionalPaddingCount)) {
        LOG(INFO) << "Failed to write chunk padding to fd " << fd.get();
    // Write checksum to buffer
    std::byte* checksumBytes = reinterpret_cast<std::byte*>(&checksumValue);
    buffer.insert(buffer.end(), checksumBytes, checksumBytes + sizeof(transaction_checksum_t));

    // Write buffer to file
    if (!android::base::WriteFully(fd, buffer.data(), buffer.size())) {
        LOG(ERROR) << "Failed to write chunk fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    return NO_ERROR;
@@ -269,19 +292,19 @@ android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const {
    if (NO_ERROR !=
        writeChunk(fd, HEADER_CHUNK, sizeof(TransactionHeader),
                   reinterpret_cast<const uint8_t*>(&mHeader))) {
        LOG(INFO) << "Failed to write transactionHeader to fd " << fd.get();
        LOG(ERROR) << "Failed to write transactionHeader to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    if (NO_ERROR != writeChunk(fd, DATA_PARCEL_CHUNK, mSent.dataSize(), mSent.data())) {
        LOG(INFO) << "Failed to write sent Parcel to fd " << fd.get();
        LOG(ERROR) << "Failed to write sent Parcel to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    if (NO_ERROR != writeChunk(fd, REPLY_PARCEL_CHUNK, mReply.dataSize(), mReply.data())) {
        LOG(INFO) << "Failed to write reply Parcel to fd " << fd.get();
        LOG(ERROR) << "Failed to write reply Parcel to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    if (NO_ERROR != writeChunk(fd, END_CHUNK, 0, NULL)) {
        LOG(INFO) << "Failed to write end chunk to fd " << fd.get();
        LOG(ERROR) << "Failed to write end chunk to fd " << fd.get();
        return UNKNOWN_ERROR;
    }
    return NO_ERROR;
Loading