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

Commit a62797e4 authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Merge "libbinder: add RpcTransportTipcAndroid" am: a417e313" into...

Merge "Merge "libbinder: add RpcTransportTipcAndroid" am: a417e313" into stage-aosp-master am: 288f935a am: b18f6c96 am: 847e08a1 am: d134eaf7

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2055506



Change-Id: I2bc5671cb03ca564c84c2a81148dab806c7a82f7
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 59290a2f d134eaf7
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
@@ -335,6 +335,34 @@ cc_library_shared {
    defaults: ["libbinder_tls_defaults"],
}

cc_library_shared {
    name: "libbinder_trusty",
    vendor: true,
    srcs: [
        "RpcTransportTipcAndroid.cpp",
        "RpcTrusty.cpp",
    ],

    shared_libs: [
        "libbinder",
        "liblog",
        "libtrusty",
        "libutils",
    ],
    static_libs: [
        "libbase",
    ],
    export_include_dirs: ["include_trusty"],

    // Most of Android doesn't need this library and shouldn't use it,
    // so we restrict its visibility to the Trusty-specific packages.
    visibility: [
        ":__subpackages__",
        "//system/core/trusty:__subpackages__",
        "//vendor:__subpackages__",
    ],
}

// For testing
cc_library_static {
    name: "libbinder_tls_static",
+218 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "RpcTransportTipcAndroid"

#include <binder/RpcSession.h>
#include <binder/RpcTransportTipcAndroid.h>
#include <log/log.h>
#include <poll.h>
#include <trusty/tipc.h>

#include "FdTrigger.h"
#include "RpcState.h"
#include "RpcTransportUtils.h"

using android::base::Error;
using android::base::Result;

namespace android {

namespace {

// RpcTransport for writing Trusty IPC clients in Android.
class RpcTransportTipcAndroid : public RpcTransport {
public:
    explicit RpcTransportTipcAndroid(android::base::unique_fd socket)
          : mSocket(std::move(socket)) {}

    status_t pollRead() override {
        if (mReadBufferPos < mReadBufferSize) {
            // We have more data in the read buffer
            return OK;
        }

        // Trusty IPC device is not a socket, so MSG_PEEK is not available
        pollfd pfd{.fd = mSocket.get(), .events = static_cast<int16_t>(POLLIN), .revents = 0};
        ssize_t ret = TEMP_FAILURE_RETRY(::poll(&pfd, 1, 0));
        if (ret < 0) {
            int savedErrno = errno;
            if (savedErrno == EAGAIN || savedErrno == EWOULDBLOCK) {
                return WOULD_BLOCK;
            }

            LOG_RPC_DETAIL("RpcTransport poll(): %s", strerror(savedErrno));
            return -savedErrno;
        }

        if (pfd.revents & POLLNVAL) {
            return BAD_VALUE;
        }
        if (pfd.revents & POLLERR) {
            return DEAD_OBJECT;
        }
        if (pfd.revents & POLLHUP) {
            return DEAD_OBJECT;
        }
        if (pfd.revents & POLLIN) {
            return OK;
        }

        return WOULD_BLOCK;
    }

    status_t interruptableWriteFully(
            FdTrigger* fdTrigger, iovec* iovs, int niovs,
            const std::optional<android::base::function_ref<status_t()>>& altPoll,
            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
            override {
        auto writeFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
            // TODO: send ancillaryFds. For now, we just abort if anyone tries
            // to send any.
            LOG_ALWAYS_FATAL_IF(ancillaryFds != nullptr && !ancillaryFds->empty(),
                                "File descriptors are not supported on Trusty yet");
            return TEMP_FAILURE_RETRY(tipc_send(mSocket.get(), iovs, niovs, nullptr, 0));
        };
        return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, writeFn, "tipc_send",
                                        POLLOUT, altPoll);
    }

    status_t interruptableReadFully(
            FdTrigger* fdTrigger, iovec* iovs, int niovs,
            const std::optional<android::base::function_ref<status_t()>>& altPoll,
            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* /*ancillaryFds*/)
            override {
        auto readFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
            // Fill the read buffer at most once per readFn call, then try to
            // return as much of it as possible. If the input iovecs are spread
            // across multiple messages that require multiple fillReadBuffer
            // calls, we expect the caller to advance the iovecs past the first
            // read and call readFn as many times as needed to get all the data
            status_t ret = fillReadBuffer();
            if (ret != OK) {
                return ret;
            }

            ssize_t processSize = 0;
            for (size_t i = 0; i < niovs && mReadBufferPos < mReadBufferSize; i++) {
                auto& iov = iovs[i];
                size_t numBytes = std::min(iov.iov_len, mReadBufferSize - mReadBufferPos);
                memcpy(iov.iov_base, mReadBuffer.get() + mReadBufferPos, numBytes);
                mReadBufferPos += numBytes;
                processSize += numBytes;
            }

            return processSize;
        };
        return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, readFn, "read",
                                        POLLIN, altPoll);
    }

private:
    status_t fillReadBuffer() {
        if (mReadBufferPos < mReadBufferSize) {
            return OK;
        }

        if (!mReadBuffer) {
            // Guarantee at least kDefaultBufferSize bytes
            mReadBufferCapacity = std::max(mReadBufferCapacity, kDefaultBufferSize);
            mReadBuffer.reset(new (std::nothrow) uint8_t[mReadBufferCapacity]);
            if (!mReadBuffer) {
                return NO_MEMORY;
            }
        }

        // Reset the size and position in case we have to exit with an error.
        // After we read a message into the buffer, we update the size
        // with the actual value.
        mReadBufferPos = 0;
        mReadBufferSize = 0;

        while (true) {
            ssize_t processSize =
                    TEMP_FAILURE_RETRY(read(mSocket.get(), mReadBuffer.get(), mReadBufferCapacity));
            if (processSize == 0) {
                return DEAD_OBJECT;
            } else if (processSize < 0) {
                int savedErrno = errno;
                if (savedErrno == EMSGSIZE) {
                    // Buffer was too small, double it and retry
                    if (__builtin_mul_overflow(mReadBufferCapacity, 2, &mReadBufferCapacity)) {
                        return NO_MEMORY;
                    }
                    mReadBuffer.reset(new (std::nothrow) uint8_t[mReadBufferCapacity]);
                    if (!mReadBuffer) {
                        return NO_MEMORY;
                    }
                    continue;
                } else {
                    LOG_RPC_DETAIL("RpcTransport fillBuffer(): %s", strerror(savedErrno));
                    return -savedErrno;
                }
            } else {
                mReadBufferSize = static_cast<size_t>(processSize);
                return OK;
            }
        }
    }

    base::unique_fd mSocket;

    // For now, we copy all the input data into a temporary buffer because
    // we might get multiple interruptableReadFully calls per message, but
    // the tipc device only allows one read call. We read every message into
    // this temporary buffer, then return pieces of it from our method.
    //
    // The special transaction GET_MAX_THREADS takes 40 bytes, so the default
    // size should start pretty high.
    static constexpr size_t kDefaultBufferSize = 64;
    std::unique_ptr<uint8_t[]> mReadBuffer;
    size_t mReadBufferPos = 0;
    size_t mReadBufferSize = 0;
    size_t mReadBufferCapacity = 0;
};

// RpcTransportCtx for Trusty.
class RpcTransportCtxTipcAndroid : public RpcTransportCtx {
public:
    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
                                               FdTrigger*) const override {
        return std::make_unique<RpcTransportTipcAndroid>(std::move(fd));
    }
    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
};

} // namespace

std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newServerCtx() const {
    return std::make_unique<RpcTransportCtxTipcAndroid>();
}

std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newClientCtx() const {
    return std::make_unique<RpcTransportCtxTipcAndroid>();
}

const char* RpcTransportCtxFactoryTipcAndroid::toCString() const {
    return "trusty";
}

std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcAndroid::make() {
    return std::unique_ptr<RpcTransportCtxFactoryTipcAndroid>(
            new RpcTransportCtxFactoryTipcAndroid());
}

} // namespace android
+46 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "RpcTrusty"

#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <binder/RpcSession.h>
#include <binder/RpcTransportTipcAndroid.h>
#include <trusty/tipc.h>

namespace android {

using android::base::unique_fd;

sp<IBinder> RpcTrustyConnect(const char* device, const char* port) {
    auto session = RpcSession::make(RpcTransportCtxFactoryTipcAndroid::make());
    auto request = [=] {
        int tipcFd = tipc_connect(device, port);
        if (tipcFd < 0) {
            LOG(ERROR) << "Failed to connect to Trusty service. Error code: " << tipcFd;
            return unique_fd();
        }
        return unique_fd(tipcFd);
    };
    if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
        LOG(ERROR) << "Failed to set up Trusty client. Error: " << statusToString(status).c_str();
        return nullptr;
    }
    return session->getRootObject();
}

} // namespace android
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Wraps the transport layer of RPC. Implementation uses Trusty IPC.

#pragma once

#include <memory>

#include <binder/RpcTransport.h>

namespace android {

// RpcTransportCtxFactory for writing Trusty IPC clients in Android.
class RpcTransportCtxFactoryTipcAndroid : public RpcTransportCtxFactory {
public:
    static std::unique_ptr<RpcTransportCtxFactory> make();

    std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
    std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
    const char* toCString() const override;

private:
    RpcTransportCtxFactoryTipcAndroid() = default;
};

} // namespace android
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <binder/IBinder.h>

namespace android {

sp<IBinder> RpcTrustyConnect(const char* device, const char* port);

} // namespace android