diff options
| author | 2022-07-15 03:22:00 +0000 | |
|---|---|---|
| committer | 2022-07-15 03:22:00 +0000 | |
| commit | 2c896d0bc96b15d3e67ade6fc238ed659f1c01d5 (patch) | |
| tree | e3f27f8c406bed2ffe4532ac4c0dae2858fbd609 | |
| parent | d7fa469fbaf9d7587b008b5dae5d0e68de74cb86 (diff) | |
| parent | 14b5187ed8091c7498b6a677481ab17ef30baf0f (diff) | |
Merge "libbinder: build on Trusty" am: c031c5f961 am: d93bb461f5 am: 01edcb276f am: 14b5187ed8
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1931393
Change-Id: I7ee574b8e58dd3910ea2230a92daf9a7250b238b
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
| -rw-r--r-- | libs/binder/RpcServer.cpp | 15 | ||||
| -rw-r--r-- | libs/binder/include/binder/RpcServer.h | 8 | ||||
| -rw-r--r-- | libs/binder/include/binder/RpcSession.h | 2 | ||||
| -rw-r--r-- | libs/binder/trusty/OS.cpp | 35 | ||||
| -rw-r--r-- | libs/binder/trusty/README.md | 39 | ||||
| -rw-r--r-- | libs/binder/trusty/RpcServerTrusty.cpp | 142 | ||||
| -rw-r--r-- | libs/binder/trusty/RpcTransportTipcTrusty.cpp | 248 | ||||
| -rw-r--r-- | libs/binder/trusty/TrustyStatus.cpp | 107 | ||||
| -rw-r--r-- | libs/binder/trusty/TrustyStatus.h | 26 | ||||
| -rw-r--r-- | libs/binder/trusty/include/binder/RpcServerTrusty.h | 100 | ||||
| -rw-r--r-- | libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h | 41 | ||||
| -rw-r--r-- | libs/binder/trusty/include/log/log.h | 122 | ||||
| -rw-r--r-- | libs/binder/trusty/logging.cpp | 166 | ||||
| -rw-r--r-- | libs/binder/trusty/rules.mk | 82 | ||||
| -rw-r--r-- | libs/binder/trusty/socket.cpp | 29 | 
15 files changed, 1154 insertions, 8 deletions
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 096d5cc5ad..49be4dd9eb 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -209,9 +209,10 @@ void RpcServer::join() {          {              RpcMutexLockGuard _l(mLock); -            RpcMaybeThread thread = RpcMaybeThread(&RpcServer::establishConnection, -                                                   sp<RpcServer>::fromExisting(this), -                                                   std::move(clientFd), addr, addrLen); +            RpcMaybeThread thread = +                    RpcMaybeThread(&RpcServer::establishConnection, +                                   sp<RpcServer>::fromExisting(this), std::move(clientFd), addr, +                                   addrLen, RpcSession::join);              auto& threadRef = mConnectingThreads[thread.get_id()];              threadRef = std::move(thread); @@ -294,8 +295,10 @@ size_t RpcServer::numUninitializedSessions() {      return mConnectingThreads.size();  } -void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd, -                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen) { +void RpcServer::establishConnection( +        sp<RpcServer>&& server, base::unique_fd clientFd, std::array<uint8_t, kRpcAddressSize> addr, +        size_t addrLen, +        std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn) {      // mShutdownTrigger can only be cleared once connection threads have joined.      // It must be set before this thread is started      LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr); @@ -478,7 +481,7 @@ void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clie      // avoid strong cycle      server = nullptr; -    RpcSession::join(std::move(session), std::move(setupResult)); +    joinFn(std::move(session), std::move(setupResult));  }  status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 9318c27cf0..52bda0e8ed 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -29,6 +29,7 @@  namespace android {  class FdTrigger; +class RpcServerTrusty;  class RpcSocketAddress;  /** @@ -189,6 +190,7 @@ public:      ~RpcServer();  private: +    friend RpcServerTrusty;      friend sp<RpcServer>;      explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx); @@ -196,8 +198,10 @@ private:      void onSessionIncomingThreadEnded() override;      static constexpr size_t kRpcAddressSize = 128; -    static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd, -                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen); +    static void establishConnection( +            sp<RpcServer>&& server, base::unique_fd clientFd, +            std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen, +            std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn);      [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);      const std::unique_ptr<RpcTransportCtx> mCtx; diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index a2b28db4a3..9d94e005c3 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -31,6 +31,7 @@ namespace android {  class Parcel;  class RpcServer; +class RpcServerTrusty;  class RpcSocketAddress;  class RpcState;  class RpcTransport; @@ -202,6 +203,7 @@ public:  private:      friend sp<RpcSession>;      friend RpcServer; +    friend RpcServerTrusty;      friend RpcState;      explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx); diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp new file mode 100644 index 0000000000..187add4a7b --- /dev/null +++ b/libs/binder/trusty/OS.cpp @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#include <openssl/rand.h> + +#include "../OS.h" + +using android::base::Result; + +namespace android { + +Result<void> setNonBlocking(android::base::borrowed_fd fd) { +    // Trusty IPC syscalls are all non-blocking by default. +    return {}; +} + +status_t getRandomBytes(uint8_t* data, size_t size) { +    int res = RAND_bytes(data, size); +    return res == 1 ? OK : UNKNOWN_ERROR; +} + +} // namespace android diff --git a/libs/binder/trusty/README.md b/libs/binder/trusty/README.md new file mode 100644 index 0000000000..1a273aab10 --- /dev/null +++ b/libs/binder/trusty/README.md @@ -0,0 +1,39 @@ +# Binder for Trusty + +This is the Trusty port of the libbinder library. +To build it, take the following steps: + +* Check out copies of the Trusty and AOSP repositories. +* Apply the patches from the `trusty_binder` topic on both repositories. +* Build Trusty normally using `build.py`. +* Run the sample AIDL test for Trusty: +  ```shell +  $ ./build-root/.../run --headless --boot-test com.android.trusty.aidl.test +  ``` + +To run the Android-Trusty IPC test, do the following: + +* Build AOSP for the `qemu_trusty_arm64-userdebug` target: +  ```shell +  $ lunch qemu_trusty_arm64-userdebug +  $ m +  ``` +* In the Trusty directory, run the emulator with the newly built Android: +  ```shell +  $ ./build-root/.../run --android /path/to/aosp +  ``` +* Using either `adb` or the shell inside the emulator itself, run the Trusty +  Binder test as root: +  ```shell +  # /data/nativetest64/vendor/trusty_binder_test/trusty_binder_test +  ``` + +## Running the AIDL compiler +For now, you will need to run the AIDL compiler manually to generate the C++ +source code for Trusty clients and services. The general syntax is: +```shell +$ aidl --lang=cpp -o <output directory> -h <output header directory> <AIDL files...> +``` + +The compiler will emit some `.cpp` files in the output directory and their +corresponding `.h` files in the header directory. diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp new file mode 100644 index 0000000000..e8b91e7a4c --- /dev/null +++ b/libs/binder/trusty/RpcServerTrusty.cpp @@ -0,0 +1,142 @@ +/* + * 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 "RpcServerTrusty" + +#include <binder/Parcel.h> +#include <binder/RpcServer.h> +#include <binder/RpcServerTrusty.h> +#include <binder/RpcThreads.h> +#include <binder/RpcTransportTipcTrusty.h> +#include <log/log.h> + +#include "../FdTrigger.h" +#include "../RpcState.h" +#include "TrustyStatus.h" + +using android::base::unexpected; + +namespace android { + +android::base::expected<sp<RpcServerTrusty>, int> RpcServerTrusty::make( +        tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl, +        size_t msgMaxSize, std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) { +    // Default is without TLS. +    if (rpcTransportCtxFactory == nullptr) +        rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make(); +    auto ctx = rpcTransportCtxFactory->newServerCtx(); +    if (ctx == nullptr) { +        return unexpected(ERR_NO_MEMORY); +    } + +    auto srv = sp<RpcServerTrusty>::make(std::move(ctx), std::move(portName), std::move(portAcl), +                                         msgMaxSize); +    if (srv == nullptr) { +        return unexpected(ERR_NO_MEMORY); +    } + +    int rc = tipc_add_service(handleSet, &srv->mTipcPort, 1, 0, &kTipcOps); +    if (rc != NO_ERROR) { +        return unexpected(rc); +    } +    return srv; +} + +RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName, +                                 std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize) +      : mRpcServer(sp<RpcServer>::make(std::move(ctx))), +        mPortName(std::move(portName)), +        mPortAcl(std::move(portAcl)) { +    mTipcPort.name = mPortName.c_str(); +    mTipcPort.msg_max_size = msgMaxSize; +    mTipcPort.msg_queue_len = 6; // Three each way +    mTipcPort.priv = this; + +    if (mPortAcl) { +        // Initialize the array of pointers to uuids. +        // The pointers in mUuidPtrs should stay valid across moves of +        // RpcServerTrusty (the addresses of a std::vector's elements +        // shouldn't change when the vector is moved), but would be invalidated +        // by a copy which is why we disable the copy constructor and assignment +        // operator for RpcServerTrusty. +        auto numUuids = mPortAcl->uuids.size(); +        mUuidPtrs.resize(numUuids); +        for (size_t i = 0; i < numUuids; i++) { +            mUuidPtrs[i] = &mPortAcl->uuids[i]; +        } + +        // Copy the contents of portAcl into the tipc_port_acl structure that we +        // pass to tipc_add_service +        mTipcPortAcl.flags = mPortAcl->flags; +        mTipcPortAcl.uuid_num = numUuids; +        mTipcPortAcl.uuids = mUuidPtrs.data(); +        mTipcPortAcl.extra_data = mPortAcl->extraData; + +        mTipcPort.acl = &mTipcPortAcl; +    } else { +        mTipcPort.acl = nullptr; +    } +} + +int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, +                                   void** ctx_p) { +    auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv)); +    server->mRpcServer->mShutdownTrigger = FdTrigger::make(); +    server->mRpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread(); + +    int rc = NO_ERROR; +    auto joinFn = [&](sp<RpcSession>&& session, RpcSession::PreJoinSetupResult&& result) { +        if (result.status != OK) { +            rc = statusToTrusty(result.status); +            return; +        } + +        /* Save the session for easy access */ +        *ctx_p = session.get(); +    }; + +    base::unique_fd clientFd(chan); +    std::array<uint8_t, RpcServer::kRpcAddressSize> addr; +    constexpr size_t addrLen = sizeof(*peer); +    memcpy(addr.data(), peer, addrLen); +    RpcServer::establishConnection(sp(server->mRpcServer), std::move(clientFd), addr, addrLen, +                                   joinFn); + +    return rc; +} + +int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* ctx) { +    auto* session = reinterpret_cast<RpcSession*>(ctx); +    status_t status = session->state()->drainCommands(session->mConnections.mIncoming[0], session, +                                                      RpcState::CommandType::ANY); +    if (status != OK) { +        LOG_RPC_DETAIL("Binder connection thread closing w/ status %s", +                       statusToString(status).c_str()); +    } + +    return NO_ERROR; +} + +void RpcServerTrusty::handleDisconnect(const tipc_port* port, handle_t chan, void* ctx) {} + +void RpcServerTrusty::handleChannelCleanup(void* ctx) { +    auto* session = reinterpret_cast<RpcSession*>(ctx); +    auto& connection = session->mConnections.mIncoming.at(0); +    LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection), +                        "bad state: connection object guaranteed to be in list"); +} + +} // namespace android diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp new file mode 100644 index 0000000000..e0d80fbe7b --- /dev/null +++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp @@ -0,0 +1,248 @@ +/* + * 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 "RpcTransportTipcTrusty" + +#include <trusty_ipc.h> + +#include <binder/RpcSession.h> +#include <binder/RpcTransportTipcTrusty.h> +#include <log/log.h> + +#include "../FdTrigger.h" +#include "../RpcState.h" +#include "TrustyStatus.h" + +namespace android { + +namespace { + +// RpcTransport for Trusty. +class RpcTransportTipcTrusty : public RpcTransport { +public: +    explicit RpcTransportTipcTrusty(android::base::unique_fd socket) : mSocket(std::move(socket)) {} +    ~RpcTransportTipcTrusty() { releaseMessage(); } + +    status_t pollRead() override { +        auto status = ensureMessage(false); +        if (status != OK) { +            return status; +        } +        return mHaveMessage ? OK : 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 { +        if (niovs < 0) { +            return BAD_VALUE; +        } + +        size_t size = 0; +        for (int i = 0; i < niovs; i++) { +            size += iovs[i].iov_len; +        } + +        ipc_msg_t msg{ +                .num_iov = static_cast<uint32_t>(niovs), +                .iov = iovs, +                .num_handles = 0, // TODO: add ancillaryFds +                .handles = nullptr, +        }; +        int rc = send_msg(mSocket.get(), &msg); +        if (rc == ERR_NOT_ENOUGH_BUFFER) { +            // Peer is blocked, wait until it unblocks. +            // TODO: when tipc supports a send-unblocked handler, +            // save the message here in a queue and retry it asynchronously +            // when the handler gets called by the library +            uevent uevt; +            do { +                rc = ::wait(mSocket.get(), &uevt, INFINITE_TIME); +                if (rc < 0) { +                    return statusFromTrusty(rc); +                } +                if (uevt.event & IPC_HANDLE_POLL_HUP) { +                    return DEAD_OBJECT; +                } +            } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED)); + +            // Retry the send, it should go through this time because +            // sending is now unblocked +            rc = send_msg(mSocket.get(), &msg); +        } +        if (rc < 0) { +            return statusFromTrusty(rc); +        } +        LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size, +                            "Sent the wrong number of bytes %d!=%zu", rc, size); + +        return OK; +    } + +    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 { +        if (niovs < 0) { +            return BAD_VALUE; +        } + +        // If iovs has one or more empty vectors at the end and +        // we somehow advance past all the preceding vectors and +        // pass some or all of the empty ones to sendmsg/recvmsg, +        // the call will return processSize == 0. In that case +        // we should be returning OK but instead return DEAD_OBJECT. +        // To avoid this problem, we make sure here that the last +        // vector at iovs[niovs - 1] has a non-zero length. +        while (niovs > 0 && iovs[niovs - 1].iov_len == 0) { +            niovs--; +        } +        if (niovs == 0) { +            // The vectors are all empty, so we have nothing to read. +            return OK; +        } + +        while (true) { +            auto status = ensureMessage(true); +            if (status != OK) { +                return status; +            } + +            ipc_msg_t msg{ +                    .num_iov = static_cast<uint32_t>(niovs), +                    .iov = iovs, +                    .num_handles = 0, // TODO: support ancillaryFds +                    .handles = nullptr, +            }; +            int rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg); +            if (rc < 0) { +                return statusFromTrusty(rc); +            } + +            size_t processSize = static_cast<size_t>(rc); +            mMessageOffset += processSize; +            LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len, +                                "Message offset exceeds length %zu/%zu", mMessageOffset, +                                mMessageInfo.len); + +            // Release the message if all of it has been read +            if (mMessageOffset == mMessageInfo.len) { +                releaseMessage(); +            } + +            while (processSize > 0 && niovs > 0) { +                auto& iov = iovs[0]; +                if (processSize < iov.iov_len) { +                    // Advance the base of the current iovec +                    iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize; +                    iov.iov_len -= processSize; +                    break; +                } + +                // The current iovec was fully written +                processSize -= iov.iov_len; +                iovs++; +                niovs--; +            } +            if (niovs == 0) { +                LOG_ALWAYS_FATAL_IF(processSize > 0, +                                    "Reached the end of iovecs " +                                    "with %zd bytes remaining", +                                    processSize); +                return OK; +            } +        } +    } + +private: +    status_t ensureMessage(bool wait) { +        int rc; +        if (mHaveMessage) { +            LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message"); +            return OK; +        } + +        /* TODO: interruptible wait, maybe with a timeout??? */ +        uevent uevt; +        rc = ::wait(mSocket.get(), &uevt, wait ? INFINITE_TIME : 0); +        if (rc < 0) { +            if (rc == ERR_TIMED_OUT && !wait) { +                // If we timed out with wait==false, then there's no message +                return OK; +            } +            return statusFromTrusty(rc); +        } +        if (!(uevt.event & IPC_HANDLE_POLL_MSG)) { +            /* No message, terminate here and leave mHaveMessage false */ +            return OK; +        } + +        rc = get_msg(mSocket.get(), &mMessageInfo); +        if (rc < 0) { +            return statusFromTrusty(rc); +        } + +        mHaveMessage = true; +        mMessageOffset = 0; +        return OK; +    } + +    void releaseMessage() { +        if (mHaveMessage) { +            put_msg(mSocket.get(), mMessageInfo.id); +            mHaveMessage = false; +        } +    } + +    base::unique_fd mSocket; + +    bool mHaveMessage = false; +    ipc_msg_info mMessageInfo; +    size_t mMessageOffset; +}; + +// RpcTransportCtx for Trusty. +class RpcTransportCtxTipcTrusty : public RpcTransportCtx { +public: +    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, +                                               FdTrigger*) const override { +        return std::make_unique<RpcTransportTipcTrusty>(std::move(fd)); +    } +    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; } +}; + +} // namespace + +std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const { +    return std::make_unique<RpcTransportCtxTipcTrusty>(); +} + +std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const { +    return std::make_unique<RpcTransportCtxTipcTrusty>(); +} + +const char* RpcTransportCtxFactoryTipcTrusty::toCString() const { +    return "trusty"; +} + +std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() { +    return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>( +            new RpcTransportCtxFactoryTipcTrusty()); +} + +} // namespace android diff --git a/libs/binder/trusty/TrustyStatus.cpp b/libs/binder/trusty/TrustyStatus.cpp new file mode 100644 index 0000000000..b1caf612bc --- /dev/null +++ b/libs/binder/trusty/TrustyStatus.cpp @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#include "TrustyStatus.h" +#include "../RpcState.h" + +namespace android { + +status_t statusFromTrusty(int rc) { +    LOG_RPC_DETAIL("Trusty error: %d", rc); +    switch (rc) { +        case NO_ERROR: +            return OK; +        case ERR_NOT_FOUND: +            return NAME_NOT_FOUND; +        case ERR_NOT_READY: +            // We get this error if we try to perform an IPC operation when the +            // channel is not ready +            return INVALID_OPERATION; +        case ERR_NO_MSG: +            return WOULD_BLOCK; +        case ERR_NO_MEMORY: +            return NO_MEMORY; +        case ERR_INVALID_ARGS: +            return BAD_VALUE; +        case ERR_NOT_ENOUGH_BUFFER: +            return WOULD_BLOCK; +        case ERR_TIMED_OUT: +            return TIMED_OUT; +        case ERR_ALREADY_EXISTS: +            return ALREADY_EXISTS; +        case ERR_CHANNEL_CLOSED: +            return DEAD_OBJECT; +        case ERR_NOT_ALLOWED: +            return INVALID_OPERATION; +        case ERR_NOT_SUPPORTED: +            return INVALID_OPERATION; +        case ERR_TOO_BIG: +            return BAD_INDEX; +        case ERR_CMD_UNKNOWN: +            return UNKNOWN_TRANSACTION; +        case ERR_BAD_STATE: +            return INVALID_OPERATION; +        case ERR_BAD_LEN: +            return NOT_ENOUGH_DATA; +        case ERR_BAD_HANDLE: +            return BAD_VALUE; +        case ERR_ACCESS_DENIED: +            return PERMISSION_DENIED; +        default: +            return UNKNOWN_ERROR; +    } +} + +int statusToTrusty(status_t status) { +    switch (status) { +        case OK: +            return NO_ERROR; +        case NO_MEMORY: +            return ERR_NO_MEMORY; +        case INVALID_OPERATION: +        case BAD_VALUE: +        case BAD_TYPE: +            return ERR_NOT_VALID; +        case NAME_NOT_FOUND: +            return ERR_NOT_FOUND; +        case PERMISSION_DENIED: +            return ERR_ACCESS_DENIED; +        case NO_INIT: +            return ERR_NOT_CONFIGURED; +        case ALREADY_EXISTS: +            return ERR_ALREADY_EXISTS; +        case DEAD_OBJECT: +            return ERR_CHANNEL_CLOSED; +        case BAD_INDEX: +            return ERR_TOO_BIG; +        case NOT_ENOUGH_DATA: +            return ERR_BAD_LEN; +        case WOULD_BLOCK: +            return ERR_NO_MSG; +        case TIMED_OUT: +            return ERR_TIMED_OUT; +        case UNKNOWN_TRANSACTION: +            return ERR_CMD_UNKNOWN; +        case FDS_NOT_ALLOWED: +            return ERR_NOT_SUPPORTED; +        case UNEXPECTED_NULL: +            return ERR_NOT_VALID; +        default: +            return ERR_GENERIC; +    } +} + +} // namespace android diff --git a/libs/binder/trusty/TrustyStatus.h b/libs/binder/trusty/TrustyStatus.h new file mode 100644 index 0000000000..fcb43f8451 --- /dev/null +++ b/libs/binder/trusty/TrustyStatus.h @@ -0,0 +1,26 @@ +/* + * 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 <uapi/err.h> +#include <utils/Errors.h> + +namespace android { + +status_t statusFromTrusty(int rc); +int statusToTrusty(status_t status); + +} // namespace android diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h new file mode 100644 index 0000000000..e8fc9f988d --- /dev/null +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -0,0 +1,100 @@ +/* + * 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 <android-base/expected.h> +#include <android-base/macros.h> +#include <android-base/unique_fd.h> +#include <binder/IBinder.h> +#include <binder/RpcServer.h> +#include <binder/RpcSession.h> +#include <binder/RpcTransport.h> +#include <utils/Errors.h> +#include <utils/RefBase.h> + +#include <map> +#include <vector> + +#include <lib/tipc/tipc_srv.h> + +namespace android { + +/** + * This is the Trusty-specific RPC server code. + */ +class RpcServerTrusty final : public virtual RefBase { +public: +    // C++ equivalent to tipc_port_acl that uses safe data structures instead of +    // raw pointers, except for |extraData| which doesn't have a good +    // equivalent. +    struct PortAcl { +        uint32_t flags; +        std::vector<const uuid> uuids; +        const void* extraData; +    }; + +    /** +     * Creates an RPC server listening on the given port and adds it to the +     * Trusty handle set at |handleSet|. +     * +     * The caller is responsible for calling tipc_run_event_loop() to start +     * the TIPC event loop after creating one or more services here. +     */ +    static android::base::expected<sp<RpcServerTrusty>, int> make( +            tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl, +            size_t msgMaxSize, +            std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr); + +    void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); } +    void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); } +    void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); } +    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) { +        mRpcServer->setPerSessionRootObject(std::move(object)); +    } +    sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); } + +private: +    // Both this class and RpcServer have multiple non-copyable fields, +    // including mPortAcl below which can't be copied because mUuidPtrs +    // holds pointers into it +    DISALLOW_COPY_AND_ASSIGN(RpcServerTrusty); + +    friend sp<RpcServerTrusty>; +    explicit RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName, +                             std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize); + +    static int handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p); +    static int handleMessage(const tipc_port* port, handle_t chan, void* ctx); +    static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx); +    static void handleChannelCleanup(void* ctx); + +    static constexpr tipc_srv_ops kTipcOps = { +            .on_connect = &handleConnect, +            .on_message = &handleMessage, +            .on_disconnect = &handleDisconnect, +            .on_channel_cleanup = &handleChannelCleanup, +    }; + +    sp<RpcServer> mRpcServer; +    std::string mPortName; +    std::shared_ptr<const PortAcl> mPortAcl; +    std::vector<const uuid*> mUuidPtrs; +    tipc_port_acl mTipcPortAcl; +    tipc_port mTipcPort; +}; + +} // namespace android diff --git a/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h new file mode 100644 index 0000000000..8eae8c2ec1 --- /dev/null +++ b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h @@ -0,0 +1,41 @@ +/* + * 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 plain sockets. +// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx. + +#pragma once + +#include <memory> + +#include <binder/RpcTransport.h> + +namespace android { + +// RpcTransportCtxFactory with TLS disabled. +class RpcTransportCtxFactoryTipcTrusty : 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: +    RpcTransportCtxFactoryTipcTrusty() = default; +}; + +} // namespace android diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h new file mode 100644 index 0000000000..bf877a3179 --- /dev/null +++ b/libs/binder/trusty/include/log/log.h @@ -0,0 +1,122 @@ +/* + * 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 + +#define BINDER_LOG_LEVEL_NONE 0 +#define BINDER_LOG_LEVEL_NORMAL 1 +#define BINDER_LOG_LEVEL_VERBOSE 2 + +#ifndef BINDER_LOG_LEVEL +#define BINDER_LOG_LEVEL BINDER_LOG_LEVEL_NORMAL +#endif // BINDER_LOG_LEVEL + +#ifndef TLOG_TAG +#ifdef LOG_TAG +#define TLOG_TAG "libbinder-" LOG_TAG +#else // LOG_TAG +#define TLOG_TAG "libbinder" +#endif // LOG_TAG +#endif // TLOG_TAG + +#include <stdlib.h> +#include <trusty_log.h> + +static inline void __ignore_va_args__(...) {} + +#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL +#define ALOGD(fmt, ...) TLOGD(fmt "\n", ##__VA_ARGS__) +#define ALOGI(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__) +#define ALOGW(fmt, ...) TLOGW(fmt "\n", ##__VA_ARGS__) +#define ALOGE(fmt, ...) TLOGE(fmt "\n", ##__VA_ARGS__) +#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL +#define ALOGD(fmt, ...)                  \ +    while (0) {                          \ +        __ignore_va_args__(__VA_ARGS__); \ +    } +#define ALOGI(fmt, ...)                  \ +    while (0) {                          \ +        __ignore_va_args__(__VA_ARGS__); \ +    } +#define ALOGW(fmt, ...)                  \ +    while (0) {                          \ +        __ignore_va_args__(__VA_ARGS__); \ +    } +#define ALOGE(fmt, ...)                  \ +    while (0) {                          \ +        __ignore_va_args__(__VA_ARGS__); \ +    } +#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL + +#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE +#define IF_ALOGV() if (TLOG_LVL >= TLOG_LVL_INFO) +#define ALOGV(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__) +#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE +#define IF_ALOGV() if (false) +#define ALOGV(fmt, ...)                  \ +    while (0) {                          \ +        __ignore_va_args__(__VA_ARGS__); \ +    } +#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE + +#define ALOGI_IF(cond, ...)                \ +    do {                                   \ +        if (cond) {                        \ +            ALOGI(#cond ": " __VA_ARGS__); \ +        }                                  \ +    } while (0) +#define ALOGE_IF(cond, ...)                \ +    do {                                   \ +        if (cond) {                        \ +            ALOGE(#cond ": " __VA_ARGS__); \ +        }                                  \ +    } while (0) +#define ALOGW_IF(cond, ...)                \ +    do {                                   \ +        if (cond) {                        \ +            ALOGW(#cond ": " __VA_ARGS__); \ +        }                                  \ +    } while (0) + +#define LOG_ALWAYS_FATAL(fmt, ...)                                \ +    do {                                                          \ +        TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \ +        abort();                                                  \ +    } while (0) +#define LOG_ALWAYS_FATAL_IF(cond, ...)                \ +    do {                                              \ +        if (cond) {                                   \ +            LOG_ALWAYS_FATAL(#cond ": " __VA_ARGS__); \ +        }                                             \ +    } while (0) +#define LOG_FATAL(fmt, ...)                                       \ +    do {                                                          \ +        TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \ +        abort();                                                  \ +    } while (0) +#define LOG_FATAL_IF(cond, ...)                \ +    do {                                       \ +        if (cond) {                            \ +            LOG_FATAL(#cond ": " __VA_ARGS__); \ +        }                                      \ +    } while (0) + +#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__) + +#define android_errorWriteLog(tag, subTag)                               \ +    do {                                                                 \ +        TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \ +    } while (0) diff --git a/libs/binder/trusty/logging.cpp b/libs/binder/trusty/logging.cpp new file mode 100644 index 0000000000..fd54744fdf --- /dev/null +++ b/libs/binder/trusty/logging.cpp @@ -0,0 +1,166 @@ +/* + * 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 TLOG_TAG "libbinder" + +#include "android-base/logging.h" + +#include <trusty_log.h> +#include <iostream> +#include <string> + +#include <android-base/macros.h> +#include <android-base/strings.h> + +namespace android { +namespace base { + +static const char* GetFileBasename(const char* file) { +    const char* last_slash = strrchr(file, '/'); +    if (last_slash != nullptr) { +        return last_slash + 1; +    } +    return file; +} + +// This splits the message up line by line, by calling log_function with a pointer to the start of +// each line and the size up to the newline character.  It sends size = -1 for the final line. +template <typename F, typename... Args> +static void SplitByLines(const char* msg, const F& log_function, Args&&... args) { +    const char* newline; +    while ((newline = strchr(msg, '\n')) != nullptr) { +        log_function(msg, newline - msg, args...); +        msg = newline + 1; +    } + +    log_function(msg, -1, args...); +} + +void DefaultAborter(const char* abort_message) { +    TLOGC("aborting: %s\n", abort_message); +    abort(); +} + +static void TrustyLogLine(const char* msg, int length, android::base::LogSeverity severity, +                          const char* tag) { +    switch (severity) { +        case VERBOSE: +        case DEBUG: +            TLOGD("%s: %s\n", tag, msg); +            break; +        case INFO: +            TLOGI("%s: %s\n", tag, msg); +            break; +        case WARNING: +            TLOGW("%s: %s\n", tag, msg); +            break; +        case ERROR: +            TLOGE("%s: %s\n", tag, msg); +            break; +        case FATAL_WITHOUT_ABORT: +        case FATAL: +            TLOGC("%s: %s\n", tag, msg); +            break; +    } +} + +void TrustyLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag, +                  const char*, unsigned int, const char* full_message) { +    SplitByLines(full_message, TrustyLogLine, severity, tag); +} + +// This indirection greatly reduces the stack impact of having lots of +// checks/logging in a function. +class LogMessageData { +public: +    LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag, +                   int error) +          : file_(GetFileBasename(file)), +            line_number_(line), +            severity_(severity), +            tag_(tag), +            error_(error) {} + +    const char* GetFile() const { return file_; } + +    unsigned int GetLineNumber() const { return line_number_; } + +    LogSeverity GetSeverity() const { return severity_; } + +    const char* GetTag() const { return tag_; } + +    int GetError() const { return error_; } + +    std::ostream& GetBuffer() { return buffer_; } + +    std::string ToString() const { return buffer_.str(); } + +private: +    std::ostringstream buffer_; +    const char* const file_; +    const unsigned int line_number_; +    const LogSeverity severity_; +    const char* const tag_; +    const int error_; + +    DISALLOW_COPY_AND_ASSIGN(LogMessageData); +}; + +LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, +                       const char* tag, int error) +      : LogMessage(file, line, severity, tag, error) {} + +LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, +                       int error) +      : data_(new LogMessageData(file, line, severity, tag, error)) {} + +LogMessage::~LogMessage() { +    // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM. +    if (!WOULD_LOG(data_->GetSeverity())) { +        return; +    } + +    // Finish constructing the message. +    if (data_->GetError() != -1) { +        data_->GetBuffer() << ": " << strerror(data_->GetError()); +    } +    std::string msg(data_->ToString()); + +    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(), +            msg.c_str()); + +    // Abort if necessary. +    if (data_->GetSeverity() == FATAL) { +        DefaultAborter(msg.c_str()); +    } +} + +std::ostream& LogMessage::stream() { +    return data_->GetBuffer(); +} + +void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, +                         const char* message) { +    TrustyLogger(DEFAULT, severity, tag ?: "<unknown>", file, line, message); +} + +bool ShouldLog(LogSeverity severity, const char* tag) { +    // This is controlled by Trusty's log level. +    return true; +} + +} // namespace base +} // namespace android diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk new file mode 100644 index 0000000000..cd81a09316 --- /dev/null +++ b/libs/binder/trusty/rules.mk @@ -0,0 +1,82 @@ +# Copyright (C) 2021 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +LIBBINDER_DIR := frameworks/native/libs/binder +LIBBASE_DIR := system/libbase +LIBCUTILS_DIR := system/core/libcutils +LIBUTILS_DIR := system/core/libutils +FMTLIB_DIR := external/fmtlib + +MODULE_SRCS := \ +	$(LOCAL_DIR)/logging.cpp \ +	$(LOCAL_DIR)/OS.cpp \ +	$(LOCAL_DIR)/RpcServerTrusty.cpp \ +	$(LOCAL_DIR)/RpcTransportTipcTrusty.cpp \ +	$(LOCAL_DIR)/TrustyStatus.cpp \ +	$(LOCAL_DIR)/socket.cpp \ +	$(LIBBINDER_DIR)/Binder.cpp \ +	$(LIBBINDER_DIR)/BpBinder.cpp \ +	$(LIBBINDER_DIR)/FdTrigger.cpp \ +	$(LIBBINDER_DIR)/IInterface.cpp \ +	$(LIBBINDER_DIR)/IResultReceiver.cpp \ +	$(LIBBINDER_DIR)/Parcel.cpp \ +	$(LIBBINDER_DIR)/RpcServer.cpp \ +	$(LIBBINDER_DIR)/RpcSession.cpp \ +	$(LIBBINDER_DIR)/RpcState.cpp \ +	$(LIBBINDER_DIR)/Stability.cpp \ +	$(LIBBINDER_DIR)/Status.cpp \ +	$(LIBBINDER_DIR)/Utils.cpp \ +	$(LIBBASE_DIR)/hex.cpp \ +	$(LIBBASE_DIR)/stringprintf.cpp \ +	$(LIBUTILS_DIR)/Errors.cpp \ +	$(LIBUTILS_DIR)/misc.cpp \ +	$(LIBUTILS_DIR)/RefBase.cpp \ +	$(LIBUTILS_DIR)/StrongPointer.cpp \ +	$(LIBUTILS_DIR)/Unicode.cpp \ + +# TODO: remove the following when libbinder supports std::string +# instead of String16 and String8 for Status and descriptors +MODULE_SRCS += \ +	$(LIBUTILS_DIR)/SharedBuffer.cpp \ +	$(LIBUTILS_DIR)/String16.cpp \ +	$(LIBUTILS_DIR)/String8.cpp \ + +# TODO: disable dump() transactions to get rid of Vector +MODULE_SRCS += \ +	$(LIBUTILS_DIR)/VectorImpl.cpp \ + +MODULE_EXPORT_INCLUDES += \ +	$(LOCAL_DIR)/include \ +	$(LIBBINDER_DIR)/include \ +	$(LIBBASE_DIR)/include \ +	$(LIBCUTILS_DIR)/include \ +	$(LIBUTILS_DIR)/include \ +	$(FMTLIB_DIR)/include \ + +MODULE_EXPORT_COMPILEFLAGS += \ +	-DBINDER_NO_KERNEL_IPC \ +	-DBINDER_RPC_SINGLE_THREADED \ +	-D__ANDROID_VNDK__ \ + +MODULE_LIBRARY_DEPS += \ +	trusty/user/base/lib/libstdc++-trusty \ +	trusty/user/base/lib/tipc \ +	external/boringssl \ + +include make/library.mk diff --git a/libs/binder/trusty/socket.cpp b/libs/binder/trusty/socket.cpp new file mode 100644 index 0000000000..02df8afb92 --- /dev/null +++ b/libs/binder/trusty/socket.cpp @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#include <log/log.h> + +// On some versions of clang, RpcServer.cpp refuses to link without accept4 +__attribute__((weak)) extern "C" int accept4(int, void*, void*, int) { +    LOG_ALWAYS_FATAL("accept4 called on Trusty"); +    return 0; +} + +// Placeholder for poll used by FdTrigger +__attribute__((weak)) extern "C" int poll(void*, long, int) { +    LOG_ALWAYS_FATAL("poll called on Trusty"); +    return 0; +}  |