Merge changes from topics "gpuMem", "timeInState"

* changes:
  Rename time_in_state.o to timeInState.o
  Rename gpu_mem.o to gpuMem.o
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index f759674..6dea91b 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1508,7 +1508,6 @@
     dprintf(out_fd, "========================================================\n");
 
     RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
-    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd);
     RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
     RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
     RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 32922ca..3b753c6 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -44,6 +44,7 @@
     defaults: ["servicemanager_defaults"],
     init_rc: ["servicemanager.rc"],
     srcs: ["main.cpp"],
+    bootstrap: true,
 }
 
 cc_binary {
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index 7584ca3..f9f042e 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -1,17 +1,17 @@
 LIBADBD_AUTH {
   global:
-    adbd_auth_new; # apex introduced=30
-    adbd_auth_delete; # apex introduced=30
-    adbd_auth_run; # apex introduced=30
-    adbd_auth_get_public_keys; #apex introduced=30
-    adbd_auth_notify_auth; # apex introduced=30
-    adbd_auth_notify_disconnect; # apex introduced=30
-    adbd_auth_prompt_user; # apex introduced=30
-    adbd_auth_prompt_user_with_id; # apex introduced=30
-    adbd_auth_tls_device_connected; # apex introduced=30
-    adbd_auth_tls_device_disconnected; # apex introduced=30
-    adbd_auth_get_max_version; # apex introduced=30
-    adbd_auth_supports_feature; # apex introduced=30
+    adbd_auth_new; # systemapi introduced=30
+    adbd_auth_delete; # systemapi introduced=30
+    adbd_auth_run; # systemapi introduced=30
+    adbd_auth_get_public_keys; # systemapi introduced=30
+    adbd_auth_notify_auth; # systemapi introduced=30
+    adbd_auth_notify_disconnect; # systemapi introduced=30
+    adbd_auth_prompt_user; # systemapi introduced=30
+    adbd_auth_prompt_user_with_id; # systemapi introduced=30
+    adbd_auth_tls_device_connected; # systemapi introduced=30
+    adbd_auth_tls_device_disconnected; # systemapi introduced=30
+    adbd_auth_get_max_version; # systemapi introduced=30
+    adbd_auth_supports_feature; # systemapi introduced=30
   local:
     *;
 };
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 49fc195..82ebdd7 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -358,6 +358,14 @@
     LOG_ALWAYS_FATAL_IF(recipient == nullptr,
                         "linkToDeath(): recipient must be non-NULL");
 
+    if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0) {
+        ALOGW("Linking to death on %s but there are no threads (yet?) listening to incoming "
+              "transactions. See ProcessState::startThreadPool and "
+              "ProcessState::setThreadPoolMaxThreadCount. Generally you should setup the binder "
+              "threadpool before other initialization steps.",
+              String8(getInterfaceDescriptor()).c_str());
+    }
+
     {
         AutoMutex _l(mLock);
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index d536219..b50cfb3 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -972,18 +972,15 @@
                             freeBuffer);
                     } else {
                         err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
-                        freeBuffer(nullptr,
-                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
-                            tr.data_size,
-                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                            tr.offsets_size/sizeof(binder_size_t));
+                        freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                                   tr.data_size,
+                                   reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
+                                   tr.offsets_size / sizeof(binder_size_t));
                     }
                 } else {
-                    freeBuffer(nullptr,
-                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
-                        tr.data_size,
-                        reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                        tr.offsets_size/sizeof(binder_size_t));
+                    freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size,
+                               reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
+                               tr.offsets_size / sizeof(binder_size_t));
                     continue;
                 }
             }
@@ -1473,17 +1470,13 @@
              ee.id, ee.command, ee.param);
 }
 
-void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
-                                size_t /*dataSize*/,
-                                const binder_size_t* /*objects*/,
-                                size_t /*objectsSize*/)
-{
+void IPCThreadState::freeBuffer(const uint8_t* data, size_t /*dataSize*/,
+                                const binder_size_t* /*objects*/, size_t /*objectsSize*/) {
     //ALOGI("Freeing parcel %p", &parcel);
     IF_LOG_COMMANDS() {
         alog << "Writing BC_FREE_BUFFER for " << data << endl;
     }
     ALOG_ASSERT(data != NULL, "Called with NULL data");
-    if (parcel != nullptr) parcel->closeFileDescriptors();
     IPCThreadState* state = self();
     state->mOut.writeInt32(BC_FREE_BUFFER);
     state->mOut.writePointer((uintptr_t)data);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 537527e..8b5d118 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2590,6 +2590,22 @@
 
     LOG_ALWAYS_FATAL_IF(session == nullptr);
 
+    if (objectTableSize != ancillaryFds.size()) {
+        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
+        relFunc(data, dataSize, nullptr, 0);
+        return BAD_VALUE;
+    }
+    for (size_t i = 0; i < objectTableSize; i++) {
+        uint32_t minObjectEnd;
+        if (__builtin_add_overflow(objectTable[i], sizeof(RpcFields::ObjectType), &minObjectEnd) ||
+            minObjectEnd >= dataSize) {
+            ALOGE("received out of range object position: %" PRIu32 " (parcel size is %zu)",
+                  objectTable[i], dataSize);
+            relFunc(data, dataSize, nullptr, 0);
+            return BAD_VALUE;
+        }
+    }
+
     freeData();
     markForRpc(session);
 
@@ -2600,12 +2616,6 @@
     mDataSize = mDataCapacity = dataSize;
     mOwner = relFunc;
 
-    if (objectTableSize != ancillaryFds.size()) {
-        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
-        freeData(); // don't leak mData
-        return BAD_VALUE;
-    }
-
     rpcFields->mObjectPositions.reserve(objectTableSize);
     for (size_t i = 0; i < objectTableSize; i++) {
         rpcFields->mObjectPositions.push_back(objectTable[i]);
@@ -2706,7 +2716,9 @@
         LOG_ALLOC("Parcel %p: freeing other owner data", this);
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
         auto* kernelFields = maybeKernelFields();
-        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+        // Close FDs before freeing, otherwise they will leak for kernel binder.
+        closeFileDescriptors();
+        mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
                kernelFields ? kernelFields->mObjectsSize : 0);
     } else {
         LOG_ALLOC("Parcel %p: freeing allocated data", this);
@@ -2891,8 +2903,13 @@
         if (objects && kernelFields && kernelFields->mObjects) {
             memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t));
         }
-        //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+        // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
+        if (kernelFields) {
+            // TODO(b/239222407): This seems wrong. We should only free FDs when
+            // they are in a truncated section of the parcel.
+            closeFileDescriptors();
+        }
+        mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
                kernelFields ? kernelFields->mObjectsSize : 0);
         mOwner = nullptr;
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 7faff47..1f311ac 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -19,6 +19,7 @@
 #include <binder/ProcessState.h>
 
 #include <android-base/result.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
@@ -420,6 +421,9 @@
 }
 
 size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
+    pthread_mutex_lock(&mThreadCountLock);
+    base::ScopeGuard detachGuard = [&]() { pthread_mutex_unlock(&mThreadCountLock); };
+
     // may actually be one more than this, if join is called
     if (mThreadPoolStarted) {
         return mCurrentThreads < mKernelStartedThreads
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 096d5cc..49be4dd 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -209,9 +209,10 @@
 
         {
             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 @@
     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 @@
     // 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/RpcState.cpp b/libs/binder/RpcState.cpp
index 0ae75cd..d063001 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -244,60 +244,63 @@
                             "New state should be impossible after terminating!");
         return;
     }
+    mTerminated = true;
 
     if (SHOULD_LOG_RPC_DETAIL) {
         ALOGE("RpcState::clear()");
         dumpLocked();
     }
 
-    // if the destructor of a binder object makes another RPC call, then calling
-    // decStrong could deadlock. So, we must hold onto these binders until
-    // mNodeMutex is no longer taken.
-    std::vector<sp<IBinder>> tempHoldBinder;
-
-    mTerminated = true;
+    // invariants
     for (auto& [address, node] : mNodeForAddress) {
-        sp<IBinder> binder = node.binder.promote();
-        LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get());
-
-        if (node.sentRef != nullptr) {
-            tempHoldBinder.push_back(node.sentRef);
+        bool guaranteedHaveBinder = node.timesSent > 0;
+        if (guaranteedHaveBinder) {
+            LOG_ALWAYS_FATAL_IF(node.sentRef == nullptr,
+                                "Binder expected to be owned with address: %" PRIu64 " %s", address,
+                                node.toString().c_str());
         }
     }
 
-    mNodeForAddress.clear();
+    // if the destructor of a binder object makes another RPC call, then calling
+    // decStrong could deadlock. So, we must hold onto these binders until
+    // mNodeMutex is no longer taken.
+    auto temp = std::move(mNodeForAddress);
+    mNodeForAddress.clear(); // RpcState isn't reusable, but for future/explicit
 
     _l.unlock();
-    tempHoldBinder.clear(); // explicit
+    temp.clear(); // explicit
 }
 
 void RpcState::dumpLocked() {
     ALOGE("DUMP OF RpcState %p", this);
     ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size());
     for (const auto& [address, node] : mNodeForAddress) {
-        sp<IBinder> binder = node.binder.promote();
-
-        const char* desc;
-        if (binder) {
-            if (binder->remoteBinder()) {
-                if (binder->remoteBinder()->isRpcBinder()) {
-                    desc = "(rpc binder proxy)";
-                } else {
-                    desc = "(binder proxy)";
-                }
-            } else {
-                desc = "(local binder)";
-            }
-        } else {
-            desc = "(null)";
-        }
-
-        ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s",
-              node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, desc);
+        ALOGE("- address: %" PRIu64 " %s", address, node.toString().c_str());
     }
     ALOGE("END DUMP OF RpcState");
 }
 
+std::string RpcState::BinderNode::toString() const {
+    sp<IBinder> strongBinder = this->binder.promote();
+
+    const char* desc;
+    if (strongBinder) {
+        if (strongBinder->remoteBinder()) {
+            if (strongBinder->remoteBinder()->isRpcBinder()) {
+                desc = "(rpc binder proxy)";
+            } else {
+                desc = "(binder proxy)";
+            }
+        } else {
+            desc = "(local binder)";
+        }
+    } else {
+        desc = "(not promotable)";
+    }
+
+    return StringPrintf("node{%p times sent: %zu times recd: %zu type: %s}",
+                        this->binder.unsafe_get(), this->timesSent, this->timesRecd, desc);
+}
 
 RpcState::CommandData::CommandData(size_t size) : mSize(size) {
     // The maximum size for regular binder is 1MB for all concurrent
@@ -581,13 +584,12 @@
     return waitForReply(connection, session, reply);
 }
 
-static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
-                               const binder_size_t* objects, size_t objectsCount) {
-    (void)p;
+static void cleanup_reply_data(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                               size_t objectsCount) {
     delete[] const_cast<uint8_t*>(data);
     (void)dataSize;
     LOG_ALWAYS_FATAL_IF(objects != nullptr);
-    LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
+    (void)objectsCount;
 }
 
 status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
@@ -643,14 +645,21 @@
     Span<const uint32_t> objectTableSpan;
     if (session->getProtocolVersion().value() >=
         RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
-        Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+        std::optional<Span<const uint8_t>> objectTableBytes =
+                parcelSpan.splitOff(rpcReply.parcelDataSize);
+        if (!objectTableBytes.has_value()) {
+            ALOGE("Parcel size larger than available bytes: %" PRId32 " vs %zu. Terminating!",
+                  rpcReply.parcelDataSize, parcelSpan.byteSize());
+            (void)session->shutdownAndWait(false);
+            return BAD_VALUE;
+        }
         std::optional<Span<const uint32_t>> maybeSpan =
-                objectTableBytes.reinterpret<const uint32_t>();
+                objectTableBytes->reinterpret<const uint32_t>();
         if (!maybeSpan.has_value()) {
             ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32
                   " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!",
                   command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize,
-                  objectTableBytes.size);
+                  objectTableBytes->size);
             return BAD_VALUE;
         }
         objectTableSpan = *maybeSpan;
@@ -787,9 +796,8 @@
                                    std::move(ancillaryFds));
 }
 
-static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize,
+static void do_nothing_to_transact_data(const uint8_t* data, size_t dataSize,
                                         const binder_size_t* objects, size_t objectsCount) {
-    (void)p;
     (void)data;
     (void)dataSize;
     (void)objects;
@@ -893,15 +901,22 @@
         Span<const uint32_t> objectTableSpan;
         if (session->getProtocolVersion().value() >
             RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
-            Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+            std::optional<Span<const uint8_t>> objectTableBytes =
+                    parcelSpan.splitOff(transaction->parcelDataSize);
+            if (!objectTableBytes.has_value()) {
+                ALOGE("Parcel size (%" PRId32 ") greater than available bytes (%zu). Terminating!",
+                      transaction->parcelDataSize, parcelSpan.byteSize());
+                (void)session->shutdownAndWait(false);
+                return BAD_VALUE;
+            }
             std::optional<Span<const uint32_t>> maybeSpan =
-                    objectTableBytes.reinterpret<const uint32_t>();
+                    objectTableBytes->reinterpret<const uint32_t>();
             if (!maybeSpan.has_value()) {
                 ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu "
                       "sizeofHeader=%zu parcelSize=%" PRId32
                       " objectTableBytesSize=%zu. Terminating!",
                       transactionData.size(), sizeof(RpcWireTransaction),
-                      transaction->parcelDataSize, objectTableBytes.size);
+                      transaction->parcelDataSize, objectTableBytes->size);
                 return BAD_VALUE;
             }
             objectTableSpan = *maybeSpan;
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 6fb2e4a..892ecd6 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -258,6 +258,8 @@
         //
 
         // (no additional data specific to remote binders)
+
+        std::string toString() const;
     };
 
     // checks if there is any reference left to a node and erases it. If erase
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 7c6d6f1..e04199c 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -48,9 +48,11 @@
     // Truncates `this` to a length of `offset` and returns a span with the
     // remainder.
     //
-    // Aborts if offset > size.
-    Span<T> splitOff(size_t offset) {
-        LOG_ALWAYS_FATAL_IF(offset > size);
+    // `std::nullopt` iff offset > size.
+    std::optional<Span<T>> splitOff(size_t offset) {
+        if (offset > size) {
+            return std::nullopt;
+        }
         Span<T> rest = {data + offset, size - offset};
         size = offset;
         return rest;
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 8ce3bc9..c01e92f 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -217,9 +217,8 @@
             void                clearCaller();
 
     static  void                threadDestructor(void *st);
-    static  void                freeBuffer(Parcel* parcel,
-                                           const uint8_t* data, size_t dataSize,
-                                           const binder_size_t* objects, size_t objectsSize);
+    static void freeBuffer(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                           size_t objectsSize);
     static  void                logExtendedError();
 
     const   sp<ProcessState>    mProcess;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 32b0ded..5469239 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -598,9 +598,9 @@
     void                print(TextOutput& to, uint32_t flags = 0) const;
 
 private:
-    typedef void        (*release_func)(Parcel* parcel,
-                                        const uint8_t* data, size_t dataSize,
-                                        const binder_size_t* objects, size_t objectsSize);
+    // `objects` and `objectsSize` always 0 for RPC Parcels.
+    typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                                 size_t objectsSize);
 
     uintptr_t           ipcData() const;
     size_t              ipcDataSize() const;
@@ -1184,10 +1184,20 @@
         c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
         if constexpr (is_pointer_equivalent_array_v<T>) {
             // could consider POD without gaps and alignment of 4.
-            auto data = reinterpret_cast<const T*>(
-                    readInplace(static_cast<size_t>(size) * sizeof(T)));
+            size_t dataLen;
+            if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) {
+                return -EOVERFLOW;
+            }
+            auto data = reinterpret_cast<const T*>(readInplace(dataLen));
             if (data == nullptr) return BAD_VALUE;
-            c->insert(c->begin(), data, data + size); // insert should do a reserve().
+            // std::vector::insert and similar methods will require type-dependent
+            // byte alignment when inserting from a const iterator such as `data`,
+            // e.g. 8 byte alignment for int64_t, and so will not work if `data`
+            // is 4 byte aligned (which is all Parcel guarantees). Copying
+            // the contents into the vector directly, where possible, circumvents
+            // this.
+            c->resize(size);
+            memcpy(c->data(), data, dataLen);
         } else if constexpr (std::is_same_v<T, bool>
                 || std::is_same_v<T, char16_t>) {
             c->reserve(size); // avoids default initialization
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 882dfbf..9679a5f 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -130,7 +130,7 @@
     void* mVMStart;
 
     // Protects thread count and wait variables below.
-    pthread_mutex_t mThreadCountLock;
+    mutable pthread_mutex_t mThreadCountLock;
     // Broadcast whenever mWaitingForThreads > 0
     pthread_cond_t mThreadCountDecrement;
     // Number of binder threads current executing a command.
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 9318c27..52bda0e 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 @@
     ~RpcServer();
 
 private:
+    friend RpcServerTrusty;
     friend sp<RpcServer>;
     explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
 
@@ -196,8 +198,10 @@
     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 a2b28db..9d94e00 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -31,6 +31,7 @@
 
 class Parcel;
 class RpcServer;
+class RpcServerTrusty;
 class RpcSocketAddress;
 class RpcState;
 class RpcTransport;
@@ -202,6 +203,7 @@
 private:
     friend sp<RpcSession>;
     friend RpcServer;
+    friend RpcServerTrusty;
     friend RpcState;
     explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
 
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index f3f2886..6bc9814 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -89,12 +89,12 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
-    ABinderProcess_joinThreadPool; # apex llndk
-    ABinderProcess_setThreadPoolMaxThreadCount; # apex llndk
-    ABinderProcess_startThreadPool; # apex llndk
-    AServiceManager_addService; # apex llndk
-    AServiceManager_checkService; # apex llndk
-    AServiceManager_getService; # apex llndk
+    ABinderProcess_joinThreadPool; # systemapi llndk
+    ABinderProcess_setThreadPoolMaxThreadCount; # systemapi llndk
+    ABinderProcess_startThreadPool; # systemapi llndk
+    AServiceManager_addService; # systemapi llndk
+    AServiceManager_checkService; # systemapi llndk
+    AServiceManager_getService; # systemapi llndk
 };
 
 LIBBINDER_NDK30 { # introduced=30
@@ -105,30 +105,30 @@
     AStatus_deleteDescription;
     AParcel_fromJavaParcel;
 
-    AIBinder_markSystemStability; # apex
+    AIBinder_markSystemStability; # systemapi
     AIBinder_markVendorStability; # llndk
-    AIBinder_markVintfStability; # apex llndk
-    AIBinder_Class_setHandleShellCommand; # apex llndk
+    AIBinder_markVintfStability; # systemapi llndk
+    AIBinder_Class_setHandleShellCommand; # systemapi llndk
 };
 
 LIBBINDER_NDK31 { # introduced=31
   global:
-    ABinderProcess_handlePolledCommands; # apex
-    ABinderProcess_setupPolling; # apex
-    AIBinder_getCallingSid; # apex
-    AIBinder_setRequestingSid; # apex
+    ABinderProcess_handlePolledCommands; # systemapi
+    ABinderProcess_setupPolling; # systemapi
+    AIBinder_getCallingSid; # systemapi
+    AIBinder_setRequestingSid; # systemapi
     AParcel_markSensitive; # systemapi llndk
-    AServiceManager_forEachDeclaredInstance; # apex llndk
-    AServiceManager_forceLazyServicesPersist; # apex llndk
-    AServiceManager_isDeclared; # apex llndk
-    AServiceManager_isUpdatableViaApex; # apex
+    AServiceManager_forEachDeclaredInstance; # systemapi llndk
+    AServiceManager_forceLazyServicesPersist; # systemapi llndk
+    AServiceManager_isDeclared; # systemapi llndk
+    AServiceManager_isUpdatableViaApex; # systemapi
     AServiceManager_reRegister; # llndk
-    AServiceManager_registerLazyService; # apex llndk
+    AServiceManager_registerLazyService; # systemapi llndk
     AServiceManager_setActiveServicesCallback; # llndk
     AServiceManager_tryUnregister; # llndk
-    AServiceManager_waitForService; # apex llndk
+    AServiceManager_waitForService; # systemapi llndk
 
-    AIBinder_forceDowngradeToSystemStability; # apex
+    AIBinder_forceDowngradeToSystemStability; # systemapi
     AIBinder_forceDowngradeToVendorStability; # llndk
 
     AIBinder_Class_getDescriptor;
@@ -146,8 +146,8 @@
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
     AIBinder_isHandlingTransaction;
-    AIBinder_setInheritRt; # apex llndk
-    AIBinder_setMinSchedulerPolicy; # apex llndk
+    AIBinder_setInheritRt; # systemapi llndk
+    AIBinder_setMinSchedulerPolicy; # systemapi llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4ed3309..e72f39c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1310,7 +1310,7 @@
      * not exceed 16 (15 Max + pool thread).
      */
     std::vector<std::thread> ts;
-    for (size_t i = 0; i < kKernelThreads - 1; i++) {
+    for (size_t i = 0; i < kKernelThreads; i++) {
         ts.push_back(std::thread([&] {
             Parcel local_reply;
             EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
@@ -1318,7 +1318,7 @@
         }));
     }
 
-    data.writeInt32(1);
+    data.writeInt32(100);
     // Give a chance for all threads to be used
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR);
 
@@ -1329,8 +1329,7 @@
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
                 StatusEq(NO_ERROR));
     replyi = reply.readInt32();
-    // No more than 16 threads should exist.
-    EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1);
+    EXPECT_EQ(replyi, kKernelThreads + 1);
 }
 
 size_t epochMillis() {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 4e41d8e..8afb403 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -930,7 +930,7 @@
 
     size_t epochMsAfter = epochMillis();
 
-    EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+    EXPECT_GE(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
 
     saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
 }
@@ -1029,13 +1029,6 @@
                 // since this session has an incoming connection w/ a threadpool, we
                 // need to manually shut it down
                 EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
-
-                proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
-                    // Flaky. Sometimes gets SIGABRT.
-                    EXPECT_TRUE((WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) ||
-                                (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT))
-                            << "server process failed: " << WaitStatusToString(wstatus);
-                });
                 proc.expectAlreadyShutdown = true;
             }
         }
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 2ca6ebd..0210237 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -7,6 +7,22 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+aidl_interface {
+    name: "binderReadParcelIface",
+    host_supported: true,
+    unstable: true,
+    srcs: [
+        "EmptyParcelable.aidl",
+        "SingleDataParcelable.aidl",
+        "GenericDataParcelable.aidl",
+    ],
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
+
 cc_fuzz {
     name: "binder_parcel_fuzzer",
     host_supported: true,
@@ -29,6 +45,8 @@
         "libcutils",
         "libhidlbase",
         "liblog",
+        "binderReadParcelIface-cpp",
+        "binderReadParcelIface-ndk",
     ],
 
     target: {
diff --git a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
new file mode 100644
index 0000000..96d6223
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+parcelable EmptyParcelable{
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
new file mode 100644
index 0000000..fc2542b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+parcelable GenericDataParcelable {
+    int data;
+    float majorVersion;
+    float minorVersion;
+    IBinder binder;
+    ParcelFileDescriptor fileDescriptor;
+    int[] array;
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
new file mode 100644
index 0000000..d62891b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+parcelable SingleDataParcelable{
+   int data;
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 7059d30..9dac2c9 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -16,6 +16,9 @@
 #define FUZZ_LOG_TAG "binder"
 
 #include "binder.h"
+#include "EmptyParcelable.h"
+#include "GenericDataParcelable.h"
+#include "SingleDataParcelable.h"
 #include "util.h"
 
 #include <android-base/hex.h>
@@ -354,6 +357,24 @@
         status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for EmptyParcelable";
+        EmptyParcelable emptyParcelable{};
+        status_t status = emptyParcelable.readFromParcel(&p);
+        FUZZ_LOG() << " status: " << status;
+    },
+    [] (const ::android::Parcel& p , FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for SingleDataParcelable";
+        SingleDataParcelable singleDataParcelable;
+        status_t status = singleDataParcelable.readFromParcel(&p);
+        FUZZ_LOG() <<" status: " << status;
+    },
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for GenericDataParcelable";
+        GenericDataParcelable genericDataParcelable;
+        status_t status = genericDataParcelable.readFromParcel(&p);
+        FUZZ_LOG() <<" status: " << status;
+    },
 };
 // clang-format on
 #pragma clang diagnostic pop
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 26d6770..af773a0 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -16,6 +16,9 @@
 #define FUZZ_LOG_TAG "binder_ndk"
 
 #include "binder_ndk.h"
+#include "aidl/EmptyParcelable.h"
+#include "aidl/GenericDataParcelable.h"
+#include "aidl/SingleDataParcelable.h"
 
 #include <android/binder_parcel_utils.h>
 #include <android/binder_parcelable_utils.h>
@@ -177,5 +180,24 @@
         PARCEL_READ(std::array<ndk::ScopedFileDescriptor COMMA 3>, ndk::AParcel_readData),
         PARCEL_READ(std::array<std::shared_ptr<ISomeInterface> COMMA 3>, ndk::AParcel_readData),
 #undef COMMA
+
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for EmptyParcelable";
+            aidl::EmptyParcelable emptyParcelable;
+            binder_status_t status = emptyParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for SingleDataParcelable";
+            aidl::SingleDataParcelable singleDataParcelable;
+            binder_status_t status = singleDataParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for GenericDataParcelable";
+            aidl::GenericDataParcelable genericDataParcelable;
+            binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
 };
 // clang-format on
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 843b6e3..6ea9708 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -19,10 +19,14 @@
 #include <android-base/unique_fd.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <vector>
+
 namespace android {
 
 // always valid or aborts
 // get a random FD for use in fuzzing, of a few different specific types
-base::unique_fd getRandomFd(FuzzedDataProvider* provider);
+//
+// may return multiple FDs (e.g. pipe), but will always return at least one
+std::vector<base::unique_fd> getRandomFds(FuzzedDataProvider* provider);
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 459fb12..27587a9 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -33,10 +33,13 @@
 /**
  * Fill parcel data, including some random binder objects and FDs
  *
+ * May insert additional FDs/binders if they own data related to the Parcel (e.g. the other
+ * end of a pipe).
+ *
  * p - the Parcel to fill
  * provider - takes ownership and completely consumes provider
  * writeHeader - optional function to write a specific header once the format of the parcel is
  *     picked (for instance, to write an interface header)
  */
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options);
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index d5aa353..32494e3 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -44,7 +44,7 @@
 
         std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
                 provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
-        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options);
 
         Parcel reply;
         (void)target->transact(code, data, &reply, flags);
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index 180a177..bef4ab6 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -35,17 +35,22 @@
 #include <sys/time.h>
 
 using android::fillRandomParcel;
+using android::RandomParcelOptions;
 using android::sp;
 using android::base::HexString;
 
-void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider,
+                      RandomParcelOptions* options) {
     // TODO: functionality to create random parcels for libhwbinder parcels
+    (void)options;
+
     std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
     p->setData(input.data(), input.size());
 }
-static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider,
+                             RandomParcelOptions* options) {
     // fill underlying parcel using functions to fill random libbinder parcel
-    fillRandomParcel(p->parcel(), std::move(provider));
+    fillRandomParcel(p->parcel(), std::move(provider), options);
 }
 
 template <typename P, typename B>
@@ -55,9 +60,11 @@
 
     FUZZ_LOG() << "backend: " << backend;
 
+    RandomParcelOptions options;
+
     P reply;
     P data;
-    fillRandomParcel(&data, std::move(provider));
+    fillRandomParcel(&data, std::move(provider), &options);
     (void)binder->transact(code, data, &reply, flag);
 }
 
@@ -73,8 +80,10 @@
     std::vector<uint8_t> instructions = provider.ConsumeBytes<uint8_t>(
             provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
 
+    RandomParcelOptions options;
+
     P p;
-    fillRandomParcel(&p, std::move(provider));
+    fillRandomParcel(&p, std::move(provider), &options);
 
     // since we are only using a byte to index
     CHECK(reads.size() <= 255) << reads.size();
@@ -103,9 +112,12 @@
     std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>(
             provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
 
+    // same options so that FDs and binders could be shared in both Parcels
+    RandomParcelOptions options;
+
     P p0, p1;
-    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()));
-    fillRandomParcel(&p1, std::move(provider));
+    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options);
+    fillRandomParcel(&p1, std::move(provider), &options);
 
     FUZZ_LOG() << "backend: " << backend;
     FUZZ_LOG() << "start: " << start << " len: " << len;
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index ab0b7e3..3fcf104 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,44 @@
 
 namespace android {
 
-base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
-    int fd = provider->PickValueInArray<std::function<int()>>({
-            []() { return ashmem_create_region("binder test region", 1024); },
-            []() { return open("/dev/null", O_RDWR); },
+using base::unique_fd;
+
+std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) {
+    std::vector<unique_fd> fds = provider->PickValueInArray<
+            std::function<std::vector<unique_fd>()>>({
+            [&]() {
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(
+                        ashmem_create_region("binder test region",
+                                             provider->ConsumeIntegralInRange<size_t>(0, 4096))));
+                return ret;
+            },
+            [&]() {
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(open("/dev/null", O_RDWR)));
+                return ret;
+            },
+            [&]() {
+                int pipefds[2];
+
+                int flags = O_CLOEXEC;
+                if (provider->ConsumeBool()) flags |= O_DIRECT;
+                if (provider->ConsumeBool()) flags |= O_NONBLOCK;
+
+                CHECK_EQ(0, pipe2(pipefds, flags));
+
+                if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]);
+
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(pipefds[0]));
+                ret.push_back(unique_fd(pipefds[1]));
+                return ret;
+            },
     })();
-    CHECK(fd >= 0);
-    return base::unique_fd(fd);
+
+    for (const auto& fd : fds) CHECK(fd.ok()) << fd.get();
+
+    return fds;
 }
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 0204f5e..51cb768 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -39,23 +39,24 @@
     CHECK(OK == p->write(data.data(), data.size()));
 }
 
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
-                      const RandomParcelOptions& options) {
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) {
+    CHECK_NE(options, nullptr);
+
     if (provider.ConsumeBool()) {
         auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
         CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
 
-        if (options.writeHeader) {
-            options.writeHeader(p, provider);
+        if (options->writeHeader) {
+            options->writeHeader(p, provider);
         }
 
         fillRandomParcelData(p, std::move(provider));
         return;
     }
 
-    if (options.writeHeader) {
-        options.writeHeader(p, provider);
+    if (options->writeHeader) {
+        options->writeHeader(p, provider);
     }
 
     while (provider.remaining_bytes() > 0) {
@@ -69,15 +70,21 @@
                 },
                 // write FD
                 [&]() {
-                    if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
-                        const base::unique_fd& fd = options.extraFds.at(
+                    if (options->extraFds.size() > 0 && provider.ConsumeBool()) {
+                        const base::unique_fd& fd = options->extraFds.at(
                                 provider.ConsumeIntegralInRange<size_t>(0,
-                                                                        options.extraFds.size() -
+                                                                        options->extraFds.size() -
                                                                                 1));
                         CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
                     } else {
-                        base::unique_fd fd = getRandomFd(&provider);
-                        CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+                        std::vector<base::unique_fd> fds = getRandomFds(&provider);
+                        CHECK(OK ==
+                              p->writeFileDescriptor(fds.begin()->release(),
+                                                     true /*takeOwnership*/));
+
+                        options->extraFds.insert(options->extraFds.end(),
+                                                 std::make_move_iterator(fds.begin() + 1),
+                                                 std::make_move_iterator(fds.end()));
                     }
                 },
                 // write binder
@@ -98,10 +105,10 @@
                                 return IInterface::asBinder(defaultServiceManager());
                             },
                             [&]() -> sp<IBinder> {
-                                if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
-                                    return options.extraBinders.at(
+                                if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
+                                    return options->extraBinders.at(
                                             provider.ConsumeIntegralInRange<
-                                                    size_t>(0, options.extraBinders.size() - 1));
+                                                    size_t>(0, options->extraBinders.size() - 1));
                                 } else {
                                     return nullptr;
                                 }
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
new file mode 100644
index 0000000..187add4
--- /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 0000000..1a273aa
--- /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 0000000..e8b91e7
--- /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 0000000..e0d80fb
--- /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 0000000..b1caf61
--- /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 0000000..fcb43f8
--- /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 0000000..e8fc9f9
--- /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 0000000..8eae8c2
--- /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 0000000..bf877a3
--- /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 0000000..fd54744
--- /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 0000000..cd81a09
--- /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 0000000..02df8af
--- /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;
+}
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 988132c..da42a96 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -2,10 +2,10 @@
   global:
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
-    AHardwareBuffer_createFromHandle; # llndk # apex
+    AHardwareBuffer_createFromHandle; # llndk # systemapi
     AHardwareBuffer_describe;
     AHardwareBuffer_getId; # introduced=31
-    AHardwareBuffer_getNativeHandle; # llndk # apex
+    AHardwareBuffer_getNativeHandle; # llndk # systemapi
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock;
     AHardwareBuffer_lockAndGetInfo; # introduced=29
@@ -23,18 +23,18 @@
     ANativeWindow_getBuffersDataSpace; # introduced=28
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
-    ANativeWindow_getLastDequeueDuration; # apex # introduced=30
-    ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
-    ANativeWindow_getLastQueueDuration; # apex # introduced=30
+    ANativeWindow_getLastDequeueDuration; # systemapi # introduced=30
+    ANativeWindow_getLastDequeueStartTime; # systemapi # introduced=30
+    ANativeWindow_getLastQueueDuration; # systemapi # introduced=30
     ANativeWindow_getWidth;
     ANativeWindow_lock;
     ANativeWindow_query; # llndk
     ANativeWindow_queryf; # llndk
     ANativeWindow_queueBuffer; # llndk
-    ANativeWindow_setCancelBufferInterceptor; # apex # introduced=30
-    ANativeWindow_setDequeueBufferInterceptor; # apex # introduced=30
-    ANativeWindow_setPerformInterceptor; # apex # introduced=30
-    ANativeWindow_setQueueBufferInterceptor; # apex # introduced=30
+    ANativeWindow_setCancelBufferInterceptor; # systemapi # introduced=30
+    ANativeWindow_setDequeueBufferInterceptor; # systemapi # introduced=30
+    ANativeWindow_setPerformInterceptor; # systemapi # introduced=30
+    ANativeWindow_setQueueBufferInterceptor; # systemapi # introduced=30
     ANativeWindow_release;
     ANativeWindow_setAutoPrerotation; # llndk
     ANativeWindow_setAutoRefresh; # llndk
@@ -45,7 +45,7 @@
     ANativeWindow_setBuffersGeometry;
     ANativeWindow_setBuffersTimestamp; # llndk
     ANativeWindow_setBuffersTransform;
-    ANativeWindow_setDequeueTimeout; # apex # introduced=30
+    ANativeWindow_setDequeueTimeout; # systemapi # introduced=30
     ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31
     ANativeWindow_setSharedBufferMode; # llndk
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 2ac41b1..231f825 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -64,7 +64,11 @@
 CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext)
       : InputMapper(deviceContext) {}
 
-CursorInputMapper::~CursorInputMapper() {}
+CursorInputMapper::~CursorInputMapper() {
+    if (mPointerController != nullptr) {
+        mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
+    }
+}
 
 uint32_t CursorInputMapper::getSources() {
     return mSource;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e60625b..0afbe11 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -755,7 +755,11 @@
     // We must support R8G8B8A8
     std::vector<VkSurfaceFormatKHR> all_formats = {
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT},
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT},
+    };
 
     if (colorspace_ext) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -777,12 +781,16 @@
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT});
     }
 
     desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT});
         if (wide_color_support) {
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
@@ -798,6 +806,9 @@
         all_formats.emplace_back(
             VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
                                VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        all_formats.emplace_back(
+            VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                               VK_COLOR_SPACE_PASS_THROUGH_EXT});
         if (wide_color_support) {
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,