Merge "Move drag event to InputDispatcher (7/n)" into sc-dev
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 1ebdc47..ec3bc61 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -49,13 +49,20 @@
         "vibrator/CommandAlwaysOnDisable.cpp",
         "vibrator/CommandAlwaysOnEnable.cpp",
         "vibrator/CommandCompose.cpp",
+        "vibrator/CommandComposePwle.cpp",
+        "vibrator/CommandGetBandwidthAmplitudeMap.cpp",
         "vibrator/CommandGetCapabilities.cpp",
         "vibrator/CommandGetCompositionDelayMax.cpp",
         "vibrator/CommandGetCompositionSizeMax.cpp",
+        "vibrator/CommandGetFrequencyMinimum.cpp",
+        "vibrator/CommandGetFrequencyResolution.cpp",
         "vibrator/CommandGetPrimitiveDuration.cpp",
+        "vibrator/CommandGetPwleCompositionSizeMax.cpp",
+        "vibrator/CommandGetPwlePrimitiveDurationMax.cpp",
         "vibrator/CommandGetQFactor.cpp",
         "vibrator/CommandGetResonantFrequency.cpp",
         "vibrator/CommandGetSupportedAlwaysOnEffects.cpp",
+        "vibrator/CommandGetSupportedBraking.cpp",
         "vibrator/CommandGetSupportedEffects.cpp",
         "vibrator/CommandGetSupportedPrimitives.cpp",
         "vibrator/CommandOff.cpp",
diff --git a/cmds/idlcli/vibrator/CommandComposePwle.cpp b/cmds/idlcli/vibrator/CommandComposePwle.cpp
new file mode 100644
index 0000000..b8308ce
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandComposePwle.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2019 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 <stdlib.h>
+
+#include <charconv>
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::ActivePwle;
+using aidl::Braking;
+using aidl::BrakingPwle;
+using aidl::PrimitivePwle;
+
+class CommandComposePwle : public Command {
+    std::string getDescription() const override { return "Compose PWLE vibration."; }
+
+    std::string getUsageSummary() const override {
+        return "[options] a <active pwle params> b <braking pwle params> ...";
+    }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{
+            {"-b", {"Block for duration of vibration."}},
+            {"a <startAmplitude> <startFrequency> <endAmplitude> <endFrequency> <duration>",
+             {"Enter the active PWLE segment parameters"}},
+            {"b <brakingMethod> <duration>", {"Enter the braking PWLE segment parameters"}},
+            {"...", {"May repeat multiple times."}},
+        };
+        return details;
+    }
+
+    int getIntFromString(std::string input, int *output) {
+        int rc = 0;
+        int value;
+        const auto res = std::from_chars(input.data(), input.data() + input.size(), value);
+        if (res.ec == std::errc::invalid_argument) {
+            std::cerr << "Invalid int argument: " << input << std::endl;
+            rc = (int)std::errc::invalid_argument;
+        } else if (res.ec == std::errc::result_out_of_range) {
+            std::cerr << "Result out of range: " << input << std::endl;
+            rc = (int)std::errc::result_out_of_range;
+        }
+        *output = value;
+        return rc;
+    }
+
+    float getFloatFromString(std::string_view input, float *output) {
+        int rc = 0;
+        errno = 0;
+        // from_chars doesn't support conversion to float so we need to first
+        // convert the string_view to string and use the C-string for strtof
+        float value = strtof(std::string(input).c_str(), NULL);
+
+        if (input == "0.0" || input == "0") {
+            return rc;
+        }
+
+        if (value <= 0.0) {
+            std::cerr << "Invalid float argument: " << input << std::endl;
+            rc = EINVAL;
+        } else if (errno == ERANGE) {
+            std::cerr << "Result out of range: " << input << std::endl;
+            rc = errno;
+        } else {
+            *output = value;
+        }
+        return rc;
+    }
+
+    Status doArgs(Args &args) override {
+        while (args.get<std::string>().value_or("").find("-") == 0) {
+            auto opt = *args.pop<std::string>();
+            if (opt == "--") {
+                break;
+            } else if (opt == "-b") {
+                mBlocking = true;
+            } else {
+                std::cerr << "Invalid Option '" << opt << "'!" << std::endl;
+                return USAGE;
+            }
+        }
+        if (args.empty()) {
+            std::cerr << "Missing arguments! Please see usage" << std::endl;
+            return USAGE;
+        }
+        while (!args.empty()) {
+            PrimitivePwle pwle;
+            auto nextArg = args.pop();
+
+            if (*nextArg == "a") {
+                auto startAmplitude = args.pop();
+                float startAmp;
+                if (getFloatFromString(*startAmplitude, &startAmp))
+                    return USAGE;
+
+                auto startFrequency = args.pop();
+                float startFreq;
+                if (getFloatFromString(*startFrequency, &startFreq))
+                    return USAGE;
+
+                auto endAmplitude = args.pop();
+                float endAmp;
+                if (getFloatFromString(*endAmplitude, &endAmp))
+                    return USAGE;
+
+                auto endFrequency = args.pop();
+                float endFreq;
+                if (getFloatFromString(*endFrequency, &endFreq))
+                    return USAGE;
+
+                auto duration = args.pop();
+                int dur;
+                if (getIntFromString(*duration, &dur))
+                    return USAGE;
+
+                ActivePwle active = {startAmp, startFreq, endAmp, endFreq, dur};
+                pwle = active;
+            } else if (*nextArg == "b") {
+                auto brakingMethod = args.pop();
+                Braking brakingMeth;
+                if (getIntFromString(*brakingMethod, (int *)&brakingMeth))
+                    return USAGE;
+
+                auto duration = args.pop();
+                int dur;
+                if (getIntFromString(*duration, &dur))
+                    return USAGE;
+
+                BrakingPwle braking = {brakingMeth, dur};
+                pwle = braking;
+            } else {
+                std::cerr << "Invalid arguments! Please see usage" << std::endl;
+                return USAGE;
+            }
+            mCompositePwle.emplace_back(std::move(pwle));
+        }
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        auto hal = getHal<aidl::IVibrator>();
+
+        if (!hal) {
+            return UNAVAILABLE;
+        }
+
+        ABinderProcess_setThreadPoolMaxThreadCount(1);
+        ABinderProcess_startThreadPool();
+
+        std::shared_ptr<VibratorCallback> callback;
+
+        if (mBlocking) {
+            callback = ndk::SharedRefBase::make<VibratorCallback>();
+        }
+
+        auto status = hal->call(&aidl::IVibrator::composePwle, mCompositePwle, callback);
+
+        if (status.isOk() && callback) {
+            callback->waitForComplete();
+        }
+
+        std::cout << "Status: " << status.getDescription() << std::endl;
+
+        return status.isOk() ? OK : ERROR;
+    }
+
+    bool mBlocking;
+    std::vector<PrimitivePwle> mCompositePwle;
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandComposePwle>("composePwle");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp b/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
new file mode 100644
index 0000000..aa01a11
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetBandwidthAmplitudeMap : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator bandwidth amplitude map.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<float> bandwidthAmplitude;
+        float frequencyMinimumHz;
+        float frequencyResolutionHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status =
+                hal->call(&aidl::IVibrator::getBandwidthAmplitudeMap, &bandwidthAmplitude);
+            statusStr = status.getDescription();
+            ret = (status.isOk() ? OK : ERROR);
+
+            status = hal->call(&aidl::IVibrator::getFrequencyMinimum, &frequencyMinimumHz);
+            ret = (status.isOk() ? OK : ERROR);
+
+            status =
+                hal->call(&aidl::IVibrator::getFrequencyResolution, &frequencyResolutionHz);
+            ret = (status.isOk() ? OK : ERROR);
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Bandwidth Amplitude Map: " << std::endl;
+        float frequency = frequencyMinimumHz;
+        for (auto &e : bandwidthAmplitude) {
+            std::cout << frequency << ":" << e << std::endl;
+            frequency += frequencyResolutionHz;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetBandwidthAmplitudeMap>(
+        "getBandwidthAmplitudeMap");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
new file mode 100644
index 0000000..504c648
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetFrequencyMinimum : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator minimum frequency in Hz.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float frequencyMinimumHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getFrequencyMinimum, &frequencyMinimumHz);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Minimum Frequency: " << frequencyMinimumHz << " Hz" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetFrequencyMinimum>("getFrequencyMinimum");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
new file mode 100644
index 0000000..de35838
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetFrequencyResolution : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator frequency resolution in Hz.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        float frequencyResolutionHz;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status =
+                hal->call(&aidl::IVibrator::getFrequencyResolution, &frequencyResolutionHz);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Frequency Resolution: " << frequencyResolutionHz << " Hz" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetFrequencyResolution>(
+        "getFrequencyResolution");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
new file mode 100644
index 0000000..b2c3551
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwleCompositionSizeMax : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PWLE composition size max.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        int32_t maxSize;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwleCompositionSizeMax, &maxSize);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Max Size: " << maxSize << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetPwleCompositionSizeMax>(
+        "getPwleCompositionSizeMax");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp b/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
new file mode 100644
index 0000000..9081973
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetPwlePrimitiveDurationMax : public Command {
+    std::string getDescription() const override {
+        return "Retrieves vibrator PWLE primitive duration size max in milliseconds.";
+    }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        int32_t maxDurationMs;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getPwlePrimitiveDurationMax, &maxDurationMs);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Primitive duration max: " << maxDurationMs << " ms" << std::endl;
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetPwlePrimitiveDurationMax>(
+        "getPwlePrimitiveDurationMax");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp b/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
new file mode 100644
index 0000000..b326e07
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 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 "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::Braking;
+
+class CommandGetSupportedBraking : public Command {
+    std::string getDescription() const override { return "List of supported braking mechanisms."; }
+
+    std::string getUsageSummary() const override { return ""; }
+
+    UsageDetails getUsageDetails() const override {
+        UsageDetails details{};
+        return details;
+    }
+
+    Status doArgs(Args &args) override {
+        if (!args.empty()) {
+            std::cerr << "Unexpected Arguments!" << std::endl;
+            return USAGE;
+        }
+        return OK;
+    }
+
+    Status doMain(Args && /*args*/) override {
+        std::string statusStr;
+        std::vector<Braking> braking;
+        Status ret;
+
+        if (auto hal = getHal<aidl::IVibrator>()) {
+            auto status = hal->call(&aidl::IVibrator::getSupportedBraking, &braking);
+            statusStr = status.getDescription();
+            ret = status.isOk() ? OK : ERROR;
+        } else {
+            return UNAVAILABLE;
+        }
+
+        std::cout << "Status: " << statusStr << std::endl;
+        std::cout << "Braking Mechanisms:" << std::endl;
+        for (auto &e : braking) {
+            std::cout << "  " << toString(e) << std::endl;
+        }
+
+        return ret;
+    }
+};
+
+static const auto Command =
+    CommandRegistry<CommandVibrator>::Register<CommandGetSupportedBraking>("getSupportedBraking");
+
+}  // namespace vibrator
+}  // namespace idlcli
+}  // namespace android
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index c17f822..eb9c528 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -325,6 +325,38 @@
                                      const ARect& destination, int32_t transform)
                                      __INTRODUCED_IN(29);
 
+/**
+ * \param source The sub-rect within the buffer's content to be rendered inside the surface's area
+ * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
+ * and height must be > 0.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceTransaction_setSourceRect(ASurfaceTransaction* transaction,
+                                       ASurfaceControl* surface_control, const ARect& source)
+                                       __INTRODUCED_IN(31);
+
+/**
+ * \param destination Specifies the rect in the parent's space where this surface will be drawn. The
+ * post source rect bounds are scaled to fit the destination rect. The surface's destination rect is
+ * clipped by the bounds of its parent. The destination rect's width and height must be > 0.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceTransaction_setPosition(ASurfaceTransaction* transaction,
+                                     ASurfaceControl* surface_control, const ARect& destination)
+                                     __INTRODUCED_IN(31);
+
+/**
+ * \param transform The transform applied after the source rect is applied to the buffer. This
+ * parameter should be set to 0 for no transform. To specify a transfrom use the
+ * NATIVE_WINDOW_TRANSFORM_* enum.
+ *
+ * Available since API level 31.
+ */
+void ASurfaceTransaction_setTransform(ASurfaceTransaction* transaction,
+                                      ASurfaceControl* surface_control, int32_t transform)
+                                      __INTRODUCED_IN(31);
 
 /**
  * Parameter for ASurfaceTransaction_setBufferTransparency().
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index a17e482..8854ba2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -121,6 +121,10 @@
         "ParcelFileDescriptor.cpp",
         "PersistableBundle.cpp",
         "ProcessState.cpp",
+        "RpcAddress.cpp",
+        "RpcConnection.cpp",
+        "RpcServer.cpp",
+        "RpcState.cpp",
         "Static.cpp",
         "Stability.cpp",
         "Status.cpp",
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index ddda024..825a821 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -21,6 +21,7 @@
 
 #include <binder/IPCThreadState.h>
 #include <binder/IResultReceiver.h>
+#include <binder/RpcConnection.h>
 #include <binder/Stability.h>
 #include <cutils/compiler.h>
 #include <utils/Log.h>
@@ -133,25 +134,56 @@
         }
         sTrackingMap[trackedUid]++;
     }
-    return new BpBinder(handle, trackedUid);
+    return new BpBinder(BinderHandle{handle}, trackedUid);
 }
 
-BpBinder::BpBinder(int32_t handle, int32_t trackedUid)
-    : mStability(0)
-    , mHandle(handle)
-    , mAlive(1)
-    , mObitsSent(0)
-    , mObituaries(nullptr)
-    , mTrackedUid(trackedUid)
-{
-    ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
+BpBinder* BpBinder::create(const sp<RpcConnection>& connection, const RpcAddress& address) {
+    LOG_ALWAYS_FATAL_IF(connection == nullptr, "BpBinder::create null connection");
 
+    // These are not currently tracked, since there is no UID or other
+    // identifier to track them with. However, if similar functionality is
+    // needed, connection objects keep track of all BpBinder objects on a
+    // per-connection basis.
+
+    return new BpBinder(SocketHandle{connection, address});
+}
+
+BpBinder::BpBinder(Handle&& handle)
+      : mStability(0),
+        mHandle(handle),
+        mAlive(true),
+        mObitsSent(false),
+        mObituaries(nullptr),
+        mTrackedUid(-1) {
     extendObjectLifetime(OBJECT_LIFETIME_WEAK);
-    IPCThreadState::self()->incWeakHandle(handle, this);
 }
 
-int32_t BpBinder::handle() const {
-    return mHandle;
+BpBinder::BpBinder(BinderHandle&& handle, int32_t trackedUid) : BpBinder(Handle(handle)) {
+    mTrackedUid = trackedUid;
+
+    ALOGV("Creating BpBinder %p handle %d\n", this, this->binderHandle());
+
+    IPCThreadState::self()->incWeakHandle(this->binderHandle(), this);
+}
+
+BpBinder::BpBinder(SocketHandle&& handle) : BpBinder(Handle(handle)) {
+    LOG_ALWAYS_FATAL_IF(rpcConnection() == nullptr, "BpBinder created w/o connection object");
+}
+
+bool BpBinder::isRpcBinder() const {
+    return std::holds_alternative<SocketHandle>(mHandle);
+}
+
+const RpcAddress& BpBinder::rpcAddress() const {
+    return std::get<SocketHandle>(mHandle).address;
+}
+
+const sp<RpcConnection>& BpBinder::rpcConnection() const {
+    return std::get<SocketHandle>(mHandle).connection;
+}
+
+int32_t BpBinder::binderHandle() const {
+    return std::get<BinderHandle>(mHandle).handle;
 }
 
 bool BpBinder::isDescriptorCached() const {
@@ -190,9 +222,10 @@
 
 status_t BpBinder::pingBinder()
 {
-    Parcel send;
+    Parcel data;
+    data.markForBinder(this);
     Parcel reply;
-    return transact(PING_TRANSACTION, send, &reply);
+    return transact(PING_TRANSACTION, data, &reply);
 }
 
 status_t BpBinder::dump(int fd, const Vector<String16>& args)
@@ -236,8 +269,13 @@
             }
         }
 
-        status_t status = IPCThreadState::self()->transact(
-            mHandle, code, data, reply, flags);
+        status_t status;
+        if (CC_UNLIKELY(isRpcBinder())) {
+            status = rpcConnection()->transact(rpcAddress(), code, data, reply, flags);
+        } else {
+            status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
+        }
+
         if (status == DEAD_OBJECT) mAlive = 0;
 
         return status;
@@ -250,6 +288,8 @@
 status_t BpBinder::linkToDeath(
     const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
 {
+    if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+
     Obituary ob;
     ob.recipient = recipient;
     ob.cookie = cookie;
@@ -267,10 +307,10 @@
                 if (!mObituaries) {
                     return NO_MEMORY;
                 }
-                ALOGV("Requesting death notification: %p handle %d\n", this, mHandle);
+                ALOGV("Requesting death notification: %p handle %d\n", this, binderHandle());
                 getWeakRefs()->incWeak(this);
                 IPCThreadState* self = IPCThreadState::self();
-                self->requestDeathNotification(mHandle, this);
+                self->requestDeathNotification(binderHandle(), this);
                 self->flushCommands();
             }
             ssize_t res = mObituaries->add(ob);
@@ -286,6 +326,8 @@
     const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
     wp<DeathRecipient>* outRecipient)
 {
+    if (isRpcBinder()) return UNKNOWN_TRANSACTION;
+
     AutoMutex _l(mLock);
 
     if (mObitsSent) {
@@ -303,9 +345,9 @@
             }
             mObituaries->removeAt(i);
             if (mObituaries->size() == 0) {
-                ALOGV("Clearing death notification: %p handle %d\n", this, mHandle);
+                ALOGV("Clearing death notification: %p handle %d\n", this, binderHandle());
                 IPCThreadState* self = IPCThreadState::self();
-                self->clearDeathNotification(mHandle, this);
+                self->clearDeathNotification(binderHandle(), this);
                 self->flushCommands();
                 delete mObituaries;
                 mObituaries = nullptr;
@@ -319,8 +361,10 @@
 
 void BpBinder::sendObituary()
 {
-    ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
-        this, mHandle, mObitsSent ? "true" : "false");
+    LOG_ALWAYS_FATAL_IF(isRpcBinder(), "Cannot send obituary for remote binder.");
+
+    ALOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n", this, binderHandle(),
+          mObitsSent ? "true" : "false");
 
     mAlive = 0;
     if (mObitsSent) return;
@@ -328,9 +372,9 @@
     mLock.lock();
     Vector<Obituary>* obits = mObituaries;
     if(obits != nullptr) {
-        ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
+        ALOGV("Clearing sent death notification: %p handle %d\n", this, binderHandle());
         IPCThreadState* self = IPCThreadState::self();
-        self->clearDeathNotification(mHandle, this);
+        self->clearDeathNotification(binderHandle(), this);
         self->flushCommands();
         mObituaries = nullptr;
     }
@@ -388,7 +432,9 @@
 
 BpBinder::~BpBinder()
 {
-    ALOGV("Destroying BpBinder %p handle %d\n", this, mHandle);
+    ALOGV("Destroying BpBinder %p handle %d\n", this, binderHandle());
+
+    if (CC_UNLIKELY(isRpcBinder())) return;
 
     IPCThreadState* ipc = IPCThreadState::self();
 
@@ -396,7 +442,8 @@
         AutoMutex _l(sTrackingLock);
         uint32_t trackedValue = sTrackingMap[mTrackedUid];
         if (CC_UNLIKELY((trackedValue & COUNTING_VALUE_MASK) == 0)) {
-            ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, mHandle);
+            ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this,
+                  binderHandle());
         } else {
             if (CC_UNLIKELY(
                 (trackedValue & LIMIT_REACHED_MASK) &&
@@ -413,26 +460,31 @@
     }
 
     if (ipc) {
-        ipc->expungeHandle(mHandle, this);
-        ipc->decWeakHandle(mHandle);
+        ipc->expungeHandle(binderHandle(), this);
+        ipc->decWeakHandle(binderHandle());
     }
 }
 
 void BpBinder::onFirstRef()
 {
-    ALOGV("onFirstRef BpBinder %p handle %d\n", this, mHandle);
+    ALOGV("onFirstRef BpBinder %p handle %d\n", this, binderHandle());
+    if (CC_UNLIKELY(isRpcBinder())) return;
     IPCThreadState* ipc = IPCThreadState::self();
-    if (ipc) ipc->incStrongHandle(mHandle, this);
+    if (ipc) ipc->incStrongHandle(binderHandle(), this);
 }
 
 void BpBinder::onLastStrongRef(const void* /*id*/)
 {
-    ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, mHandle);
+    ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
+    if (CC_UNLIKELY(isRpcBinder())) {
+        (void)rpcConnection()->sendDecStrong(rpcAddress());
+        return;
+    }
     IF_ALOGV() {
         printRefs();
     }
     IPCThreadState* ipc = IPCThreadState::self();
-    if (ipc) ipc->decStrongHandle(mHandle);
+    if (ipc) ipc->decStrongHandle(binderHandle());
 
     mLock.lock();
     Vector<Obituary>* obits = mObituaries;
@@ -442,7 +494,7 @@
                   mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
         }
 
-        if (ipc) ipc->clearDeathNotification(mHandle, this);
+        if (ipc) ipc->clearDeathNotification(binderHandle(), this);
         mObituaries = nullptr;
     }
     mLock.unlock();
@@ -457,9 +509,12 @@
 
 bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/)
 {
-    ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, mHandle);
+    // RPC binder doesn't currently support inc from weak binders
+    if (CC_UNLIKELY(isRpcBinder())) return false;
+
+    ALOGV("onIncStrongAttempted BpBinder %p handle %d\n", this, binderHandle());
     IPCThreadState* ipc = IPCThreadState::self();
-    return ipc ? ipc->attemptIncStrongHandle(mHandle) == NO_ERROR : false;
+    return ipc ? ipc->attemptIncStrongHandle(binderHandle()) == NO_ERROR : false;
 }
 
 uint32_t BpBinder::getBinderProxyCount(uint32_t uid)
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index e4ac4b4..8676955 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -26,6 +26,22 @@
 
 namespace android {
 
+std::string hexString(const void* bytes, size_t len) {
+    if (bytes == nullptr) return "<null>";
+
+    const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
+    const char chars[] = "0123456789abcdef";
+    std::string result;
+    result.resize(len * 2);
+
+    for (size_t i = 0; i < len; i++) {
+        result[2 * i] = chars[bytes8[i] >> 4];
+        result[2 * i + 1] = chars[bytes8[i] & 0xf];
+    }
+
+    return result;
+}
+
 // ---------------------------------------------------------------------
 
 static const char indentStr[] =
diff --git a/libs/binder/Debug.h b/libs/binder/Debug.h
index ac71e00..68d811b 100644
--- a/libs/binder/Debug.h
+++ b/libs/binder/Debug.h
@@ -17,13 +17,13 @@
 #pragma once
 
 #include <stdint.h>
-#include <sys/cdefs.h>
 #include <sys/types.h>
+#include <string>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-__BEGIN_DECLS
+std::string hexString(const void* data, size_t size);
 
 const char* stringForIndent(int32_t indentLevel);
 
@@ -40,7 +40,5 @@
 
 ssize_t getBinderKernelReferences(size_t count, uintptr_t* buf);
 
-__END_DECLS
-
 // ---------------------------------------------------------------------------
 } // namespace android
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 79a11d2..406bd54 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -689,6 +689,8 @@
                                   uint32_t code, const Parcel& data,
                                   Parcel* reply, uint32_t flags)
 {
+    LOG_ALWAYS_FATAL_IF(data.isForRpc(), "Parcel constructed for RPC, but being used with binder.");
+
     status_t err;
 
     flags |= TF_ACCEPT_FDS;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 3773760..6f34159 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -48,6 +48,7 @@
 #include <utils/String16.h>
 
 #include <private/binder/binder_module.h>
+#include "RpcState.h"
 #include "Static.h"
 #include "Utils.h"
 
@@ -191,6 +192,22 @@
 
 status_t Parcel::flattenBinder(const sp<IBinder>& binder)
 {
+    if (isForRpc()) {
+        if (binder) {
+            status_t status = writeInt32(1); // non-null
+            if (status != OK) return status;
+            RpcAddress address = RpcAddress::zero();
+            status = mConnection->state()->onBinderLeaving(mConnection, binder, &address);
+            if (status != OK) return status;
+            status = address.writeToParcel(this);
+            if (status != OK) return status;
+        } else {
+            status_t status = writeInt32(0); // null
+            if (status != OK) return status;
+        }
+        return finishFlattenBinder(binder);
+    }
+
     flat_binder_object obj;
     obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
 
@@ -205,8 +222,13 @@
             BpBinder *proxy = binder->remoteBinder();
             if (proxy == nullptr) {
                 ALOGE("null proxy");
+            } else {
+                if (proxy->isRpcBinder()) {
+                    ALOGE("Sending a socket binder over RPC is prohibited");
+                    return INVALID_OPERATION;
+                }
             }
-            const int32_t handle = proxy ? proxy->getPrivateAccessorForHandle().handle() : 0;
+            const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
             obj.hdr.type = BINDER_TYPE_HANDLE;
             obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
             obj.handle = handle;
@@ -245,6 +267,26 @@
 
 status_t Parcel::unflattenBinder(sp<IBinder>* out) const
 {
+    if (isForRpc()) {
+        LOG_ALWAYS_FATAL_IF(mConnection == nullptr,
+                            "RpcConnection required to read from remote parcel");
+
+        int32_t isNull;
+        status_t status = readInt32(&isNull);
+        if (status != OK) return status;
+
+        sp<IBinder> binder;
+
+        if (isNull & 1) {
+            auto addr = RpcAddress::zero();
+            status_t status = addr.readFromParcel(*this);
+            if (status != OK) return status;
+            binder = mConnection->state()->onBinderEntering(mConnection, addr);
+        }
+
+        return finishUnflattenBinder(binder, out);
+    }
+
     const flat_binder_object* flat = readObject(false);
 
     if (flat) {
@@ -511,6 +553,21 @@
     mDeallocZero = true;
 }
 
+void Parcel::markForBinder(const sp<IBinder>& binder) {
+    if (binder && binder->remoteBinder() && binder->remoteBinder()->isRpcBinder()) {
+        markForRpc(binder->remoteBinder()->getPrivateAccessorForId().rpcConnection());
+    }
+}
+
+void Parcel::markForRpc(const sp<RpcConnection>& connection) {
+    LOG_ALWAYS_FATAL_IF(connection == nullptr, "markForRpc requires connection");
+    mConnection = connection;
+}
+
+bool Parcel::isForRpc() const {
+    return mConnection != nullptr;
+}
+
 void Parcel::updateWorkSourceRequestHeaderPosition() const {
     // Only update the request headers once. We only want to point
     // to the first headers read/written.
@@ -1070,6 +1127,11 @@
 
 status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership)
 {
+    if (isForRpc()) {
+        ALOGE("Cannot write file descriptor to remote binder.");
+        return BAD_TYPE;
+    }
+
     flat_binder_object obj;
     obj.hdr.type = BINDER_TYPE_FD;
     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
@@ -2413,6 +2475,7 @@
     mDataPos = 0;
     ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
     ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
+    mConnection = nullptr;
     mObjects = nullptr;
     mObjectsSize = 0;
     mObjectsCapacity = 0;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index edadcd5..abb792e 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -205,10 +205,12 @@
 //
 // Returns -1 in case of failure, otherwise the strong reference count.
 ssize_t ProcessState::getStrongRefCountForNode(const sp<BpBinder>& binder) {
+    if (binder->isRpcBinder()) return -1;
+
     binder_node_info_for_ref info;
     memset(&info, 0, sizeof(binder_node_info_for_ref));
 
-    info.handle = binder->getPrivateAccessorForHandle().handle();
+    info.handle = binder->getPrivateAccessorForId().binderHandle();
 
     status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
 
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
new file mode 100644
index 0000000..5c32320
--- /dev/null
+++ b/libs/binder/RpcAddress.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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 <binder/RpcAddress.h>
+
+#include <binder/Parcel.h>
+
+#include "Debug.h"
+#include "RpcState.h"
+#include "RpcWireFormat.h"
+
+namespace android {
+
+RpcAddress RpcAddress::zero() {
+    return RpcAddress();
+}
+
+bool RpcAddress::isZero() const {
+    RpcWireAddress ZERO{0};
+    return memcmp(mRawAddr.get(), &ZERO, sizeof(RpcWireAddress)) == 0;
+}
+
+static void ReadRandomBytes(uint8_t* buf, size_t len) {
+    int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+    if (fd == -1) {
+        ALOGE("%s: cannot read /dev/urandom", __func__);
+        return;
+    }
+
+    size_t n;
+    while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
+        len -= n;
+        buf += n;
+    }
+    if (len > 0) {
+        ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
+    }
+    close(fd);
+}
+
+RpcAddress RpcAddress::unique() {
+    RpcAddress ret;
+    ReadRandomBytes((uint8_t*)ret.mRawAddr.get(), sizeof(RpcWireAddress));
+    LOG_RPC_DETAIL("Creating new address: %s", ret.toString().c_str());
+    return ret;
+}
+
+RpcAddress RpcAddress::fromRawEmbedded(const RpcWireAddress* raw) {
+    RpcAddress addr;
+    memcpy(addr.mRawAddr.get(), raw, sizeof(RpcWireAddress));
+    return addr;
+}
+
+const RpcWireAddress& RpcAddress::viewRawEmbedded() const {
+    return *mRawAddr.get();
+}
+
+bool RpcAddress::operator<(const RpcAddress& rhs) const {
+    return std::memcmp(mRawAddr.get(), rhs.mRawAddr.get(), sizeof(RpcWireAddress)) < 0;
+}
+
+std::string RpcAddress::toString() const {
+    return hexString(mRawAddr.get(), sizeof(RpcWireAddress));
+}
+
+status_t RpcAddress::writeToParcel(Parcel* parcel) const {
+    return parcel->write(mRawAddr.get(), sizeof(RpcWireAddress));
+}
+
+status_t RpcAddress::readFromParcel(const Parcel& parcel) {
+    return parcel.read(mRawAddr.get(), sizeof(RpcWireAddress));
+}
+
+RpcAddress::~RpcAddress() {}
+RpcAddress::RpcAddress() : mRawAddr(std::make_shared<RpcWireAddress>()) {}
+
+} // namespace android
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
new file mode 100644
index 0000000..83a1618
--- /dev/null
+++ b/libs/binder/RpcConnection.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2020 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 "RpcConnection"
+
+#include <binder/RpcConnection.h>
+
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+
+#include "RpcState.h"
+#include "RpcWireFormat.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#if defined(__GLIBC__)
+extern "C" pid_t gettid();
+#endif
+
+namespace android {
+
+using base::unique_fd;
+
+RpcConnection::RpcConnection() {
+    LOG_RPC_DETAIL("RpcConnection created %p", this);
+
+    mState = std::make_unique<RpcState>();
+}
+RpcConnection::~RpcConnection() {
+    LOG_RPC_DETAIL("RpcConnection destroyed %p", this);
+}
+
+sp<RpcConnection> RpcConnection::make() {
+    return new RpcConnection;
+}
+
+bool RpcConnection::setupUnixDomainServer(const char* path) {
+    LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Only supports one server now");
+
+    unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    if (serverFd == -1) {
+        ALOGE("Could not create socket at %s: %s", path, strerror(errno));
+        return false;
+    }
+
+    struct sockaddr_un addr = {
+            .sun_family = AF_UNIX,
+    };
+
+    unsigned int pathLen = strlen(path) + 1;
+    LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen);
+    memcpy(addr.sun_path, path, pathLen);
+
+    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) {
+        ALOGE("Could not bind socket at %s: %s", path, strerror(errno));
+        return false;
+    }
+
+    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+        ALOGE("Could not listen socket at %s: %s", path, strerror(errno));
+        return false;
+    }
+
+    mServer = std::move(serverFd);
+    return true;
+}
+
+bool RpcConnection::addUnixDomainClient(const char* path) {
+    LOG_RPC_DETAIL("Connecting on path: %s", path);
+
+    unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    if (serverFd == -1) {
+        ALOGE("Could not create socket at %s: %s", path, strerror(errno));
+        return false;
+    }
+
+    struct sockaddr_un addr = {
+            .sun_family = AF_UNIX,
+    };
+
+    unsigned int pathLen = strlen(path) + 1;
+    LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen);
+    memcpy(addr.sun_path, path, pathLen);
+
+    if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) {
+        ALOGE("Could not connect socket at %s: %s", path, strerror(errno));
+        return false;
+    }
+
+    LOG_RPC_DETAIL("Unix domain client with fd %d", serverFd.get());
+
+    addClient(std::move(serverFd));
+    return true;
+}
+
+sp<IBinder> RpcConnection::getRootObject() {
+    ExclusiveSocket socket(this, SocketUse::CLIENT);
+    return state()->getRootObject(socket.fd(), this);
+}
+
+status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data,
+                                 Parcel* reply, uint32_t flags) {
+    ExclusiveSocket socket(this,
+                           (flags & IBinder::FLAG_ONEWAY) ? SocketUse::CLIENT_ASYNC
+                                                          : SocketUse::CLIENT);
+    return state()->transact(socket.fd(), address, code, data, this, reply, flags);
+}
+
+status_t RpcConnection::sendDecStrong(const RpcAddress& address) {
+    ExclusiveSocket socket(this, SocketUse::CLIENT_REFCOUNT);
+    return state()->sendDecStrong(socket.fd(), address);
+}
+
+void RpcConnection::join() {
+    // establish a connection
+    {
+        struct sockaddr_un clientSa;
+        socklen_t clientSaLen = sizeof(clientSa);
+
+        unique_fd clientFd(TEMP_FAILURE_RETRY(
+                accept4(mServer.get(), (struct sockaddr*)&clientSa, &clientSaLen, SOCK_CLOEXEC)));
+        if (clientFd < 0) {
+            // If this log becomes confusing, should save more state from setupUnixDomainServer
+            // in order to output here.
+            ALOGE("Could not accept4 socket: %s", strerror(errno));
+            return;
+        }
+
+        LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+        addServer(std::move(clientFd));
+    }
+
+    // We may not use the connection we just established (two threads might
+    // establish connections for each other), but for now, just use one
+    // server/socket connection.
+    ExclusiveSocket socket(this, SocketUse::SERVER);
+
+    while (true) {
+        status_t error = state()->getAndExecuteCommand(socket.fd(), this);
+
+        if (error != OK) {
+            ALOGI("Binder socket thread closing w/ status %s", statusToString(error).c_str());
+            return;
+        }
+    }
+}
+
+void RpcConnection::setForServer(const wp<RpcServer>& server) {
+    mForServer = server;
+}
+
+wp<RpcServer> RpcConnection::server() {
+    return mForServer;
+}
+
+void RpcConnection::addClient(base::unique_fd&& fd) {
+    std::lock_guard<std::mutex> _l(mSocketMutex);
+    sp<ConnectionSocket> connection = new ConnectionSocket();
+    connection->fd = std::move(fd);
+    mClients.push_back(connection);
+}
+
+void RpcConnection::addServer(base::unique_fd&& fd) {
+    std::lock_guard<std::mutex> _l(mSocketMutex);
+    sp<ConnectionSocket> connection = new ConnectionSocket();
+    connection->fd = std::move(fd);
+    mServers.push_back(connection);
+}
+
+RpcConnection::ExclusiveSocket::ExclusiveSocket(const sp<RpcConnection>& connection, SocketUse use)
+      : mConnection(connection) {
+    pid_t tid = gettid();
+    std::unique_lock<std::mutex> _l(mConnection->mSocketMutex);
+
+    mConnection->mWaitingThreads++;
+    while (true) {
+        sp<ConnectionSocket> exclusive;
+        sp<ConnectionSocket> available;
+
+        // CHECK FOR DEDICATED CLIENT SOCKET
+        //
+        // A server/looper should always use a dedicated connection.
+        if (use != SocketUse::SERVER) {
+            findSocket(tid, &exclusive, &available, mConnection->mClients,
+                       mConnection->mClientsOffset);
+
+            // WARNING: this assumes a server cannot request its client to send
+            // a transaction, as mServers is excluded below.
+            //
+            // Imagine we have more than one thread in play, and a single thread
+            // sends a synchronous, then an asynchronous command. Imagine the
+            // asynchronous command is sent on the first client socket. Then, if
+            // we naively send a synchronous command to that same socket, the
+            // thread on the far side might be busy processing the asynchronous
+            // command. So, we move to considering the second available thread
+            // for subsequent calls.
+            if (use == SocketUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
+                mConnection->mClientsOffset =
+                        (mConnection->mClientsOffset + 1) % mConnection->mClients.size();
+            }
+        }
+
+        // USE SERVING SOCKET (to start serving or for nested transaction)
+        //
+        // asynchronous calls cannot be nested
+        if (use != SocketUse::CLIENT_ASYNC) {
+            // servers should start serving on an available thread only
+            // otherwise, this should only be a nested call
+            bool useAvailable = use == SocketUse::SERVER;
+
+            findSocket(tid, &exclusive, (useAvailable ? &available : nullptr),
+                       mConnection->mServers, 0 /* index hint */);
+        }
+
+        // if our thread is already using a connection, prioritize using that
+        if (exclusive != nullptr) {
+            mSocket = exclusive;
+            mReentrant = true;
+            break;
+        } else if (available != nullptr) {
+            mSocket = available;
+            mSocket->exclusiveTid = tid;
+            break;
+        }
+
+        LOG_ALWAYS_FATAL_IF(use == SocketUse::SERVER, "Must create connection to join one.");
+
+        // in regular binder, this would usually be a deadlock :)
+        LOG_ALWAYS_FATAL_IF(mConnection->mClients.size() == 0,
+                            "Not a client of any connection. You must create a connection to an "
+                            "RPC server to make any non-nested (e.g. oneway or on another thread) "
+                            "calls.");
+
+        LOG_RPC_DETAIL("No available connection (have %zu clients and %zu servers). Waiting...",
+                       mConnection->mClients.size(), mConnection->mServers.size());
+        mConnection->mSocketCv.wait(_l);
+    }
+    mConnection->mWaitingThreads--;
+}
+
+void RpcConnection::ExclusiveSocket::findSocket(pid_t tid, sp<ConnectionSocket>* exclusive,
+                                                sp<ConnectionSocket>* available,
+                                                std::vector<sp<ConnectionSocket>>& sockets,
+                                                size_t socketsIndexHint) {
+    LOG_ALWAYS_FATAL_IF(sockets.size() > 0 && socketsIndexHint >= sockets.size(),
+                        "Bad index %zu >= %zu", socketsIndexHint, sockets.size());
+
+    if (*exclusive != nullptr) return; // consistent with break below
+
+    for (size_t i = 0; i < sockets.size(); i++) {
+        sp<ConnectionSocket>& socket = sockets[(i + socketsIndexHint) % sockets.size()];
+
+        // take first available connection (intuition = caching)
+        if (available && *available == nullptr && socket->exclusiveTid == std::nullopt) {
+            *available = socket;
+            continue;
+        }
+
+        // though, prefer to take connection which is already inuse by this thread
+        // (nested transactions)
+        if (exclusive && socket->exclusiveTid == tid) {
+            *exclusive = socket;
+            break; // consistent with return above
+        }
+    }
+}
+
+RpcConnection::ExclusiveSocket::~ExclusiveSocket() {
+    // reentrant use of a connection means something less deep in the call stack
+    // is using this fd, and it retains the right to it. So, we don't give up
+    // exclusive ownership, and no thread is freed.
+    if (!mReentrant) {
+        std::unique_lock<std::mutex> _l(mConnection->mSocketMutex);
+        mSocket->exclusiveTid = std::nullopt;
+        if (mConnection->mWaitingThreads > 0) {
+            _l.unlock();
+            mConnection->mSocketCv.notify_one();
+        }
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
new file mode 100644
index 0000000..df07916
--- /dev/null
+++ b/libs/binder/RpcServer.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 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 "RpcServer"
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <vector>
+
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <log/log.h>
+#include "RpcState.h"
+
+#include "RpcWireFormat.h"
+
+namespace android {
+
+using base::unique_fd;
+
+RpcServer::RpcServer() {}
+RpcServer::~RpcServer() {}
+
+sp<RpcServer> RpcServer::make() {
+    return new RpcServer;
+}
+
+void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
+    mAgreedExperimental = true;
+}
+
+sp<RpcConnection> RpcServer::addClientConnection() {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+
+    auto connection = RpcConnection::make();
+    connection->setForServer(this);
+    mConnections.push_back(connection);
+    return connection;
+}
+
+void RpcServer::setRootObject(const sp<IBinder>& binder) {
+    LOG_ALWAYS_FATAL_IF(mRootObject != nullptr, "There can only be one root object");
+    mRootObject = binder;
+}
+
+sp<IBinder> RpcServer::getRootObject() {
+    return mRootObject;
+}
+
+} // namespace android
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
new file mode 100644
index 0000000..64e842e
--- /dev/null
+++ b/libs/binder/RpcState.cpp
@@ -0,0 +1,663 @@
+/*
+ * Copyright (C) 2020 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 "RpcState"
+
+#include "RpcState.h"
+
+#include <binder/BpBinder.h>
+#include <binder/RpcServer.h>
+
+#include "Debug.h"
+#include "RpcWireFormat.h"
+
+#include <inttypes.h>
+
+namespace android {
+
+RpcState::RpcState() {}
+RpcState::~RpcState() {}
+
+status_t RpcState::onBinderLeaving(const sp<RpcConnection>& connection, const sp<IBinder>& binder,
+                                   RpcAddress* outAddress) {
+    bool isRemote = binder->remoteBinder();
+    bool isRpc = isRemote && binder->remoteBinder()->isRpcBinder();
+
+    if (isRpc && binder->remoteBinder()->getPrivateAccessorForId().rpcConnection() != connection) {
+        // We need to be able to send instructions over the socket for how to
+        // connect to a different server, and we also need to let the host
+        // process know that this is happening.
+        ALOGE("Canot send binder from unrelated binder RPC connection.");
+        return INVALID_OPERATION;
+    }
+
+    if (isRemote && !isRpc) {
+        // Without additional work, this would have the effect of using this
+        // process to proxy calls from the socket over to the other process, and
+        // it would make those calls look like they come from us (not over the
+        // sockets). In order to make this work transparently like binder, we
+        // would instead need to send instructions over the socket for how to
+        // connect to the host process, and we also need to let the host process
+        // know this was happening.
+        ALOGE("Cannot send binder proxy %p over sockets", binder.get());
+        return INVALID_OPERATION;
+    }
+
+    std::lock_guard<std::mutex> _l(mNodeMutex);
+
+    // TODO(b/182939933): maybe move address out of BpBinder, and keep binder->address map
+    // in RpcState
+    for (auto& [addr, node] : mNodeForAddress) {
+        if (binder == node.binder) {
+            if (isRpc) {
+                const RpcAddress& actualAddr =
+                        binder->remoteBinder()->getPrivateAccessorForId().rpcAddress();
+                // TODO(b/182939933): this is only checking integrity of data structure
+                // a different data structure doesn't need this
+                LOG_ALWAYS_FATAL_IF(addr < actualAddr, "Address mismatch");
+                LOG_ALWAYS_FATAL_IF(actualAddr < addr, "Address mismatch");
+            }
+            node.timesSent++;
+            node.sentRef = binder; // might already be set
+            *outAddress = addr;
+            return OK;
+        }
+    }
+    LOG_ALWAYS_FATAL_IF(isRpc, "RPC binder must have known address at this point");
+
+    auto&& [it, inserted] = mNodeForAddress.insert({RpcAddress::unique(),
+                                                    BinderNode{
+                                                            .binder = binder,
+                                                            .timesSent = 1,
+                                                            .sentRef = binder,
+                                                    }});
+    // TODO(b/182939933): better organization could avoid needing this log
+    LOG_ALWAYS_FATAL_IF(!inserted);
+
+    *outAddress = it->first;
+    return OK;
+}
+
+sp<IBinder> RpcState::onBinderEntering(const sp<RpcConnection>& connection,
+                                       const RpcAddress& address) {
+    std::unique_lock<std::mutex> _l(mNodeMutex);
+
+    if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
+        sp<IBinder> binder = it->second.binder.promote();
+
+        // implicitly have strong RPC refcount, since we received this binder
+        it->second.timesRecd++;
+
+        _l.unlock();
+
+        // We have timesRecd RPC refcounts, but we only need to hold on to one
+        // when we keep the object. All additional dec strongs are sent
+        // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
+        (void)connection->sendDecStrong(address);
+
+        return binder;
+    }
+
+    auto&& [it, inserted] = mNodeForAddress.insert({address, BinderNode{}});
+    LOG_ALWAYS_FATAL_IF(!inserted, "Failed to insert binder when creating proxy");
+
+    // Currently, all binders are assumed to be part of the same connection (no
+    // device global binders in the RPC world).
+    sp<IBinder> binder = BpBinder::create(connection, it->first);
+    it->second.binder = binder;
+    it->second.timesRecd = 1;
+    return binder;
+}
+
+size_t RpcState::countBinders() {
+    std::lock_guard<std::mutex> _l(mNodeMutex);
+    return mNodeForAddress.size();
+}
+
+void RpcState::dump() {
+    std::lock_guard<std::mutex> _l(mNodeMutex);
+    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:%s type:%s",
+              node.binder.unsafe_get(), node.timesSent, node.timesRecd, address.toString().c_str(),
+              desc);
+    }
+    ALOGE("END DUMP OF RpcState");
+}
+
+void RpcState::terminate() {
+    if (SHOULD_LOG_RPC_DETAIL) {
+        ALOGE("RpcState::terminate()");
+        dump();
+    }
+
+    // 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;
+
+    {
+        std::lock_guard<std::mutex> _l(mNodeMutex);
+        mTerminated = true;
+        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);
+            }
+        }
+
+        mNodeForAddress.clear();
+    }
+}
+
+bool RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* data, size_t size) {
+    LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str());
+
+    if (size > std::numeric_limits<ssize_t>::max()) {
+        ALOGE("Cannot send %s at size %zu (too big)", what, size);
+        terminate();
+        return false;
+    }
+
+    ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, 0));
+
+    if (sent < 0 || sent != static_cast<ssize_t>(size)) {
+        ALOGE("Failed to send %s (sent %zd of %zu bytes) on fd %d, error: %s", what, sent, size,
+              fd.get(), strerror(errno));
+
+        terminate();
+        return false;
+    }
+
+    return true;
+}
+
+bool RpcState::rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size) {
+    if (size > std::numeric_limits<ssize_t>::max()) {
+        ALOGE("Cannot rec %s at size %zu (too big)", what, size);
+        terminate();
+        return false;
+    }
+
+    ssize_t recd = TEMP_FAILURE_RETRY(recv(fd.get(), data, size, MSG_WAITALL));
+
+    if (recd < 0 || recd != static_cast<ssize_t>(size)) {
+        terminate();
+
+        if (recd == 0 && errno == 0) {
+            LOG_RPC_DETAIL("No more data when trying to read %s on fd %d", what, fd.get());
+            return false;
+        }
+
+        ALOGE("Failed to read %s (received %zd of %zu bytes) on fd %d, error: %s", what, recd, size,
+              fd.get(), strerror(errno));
+        return false;
+    } else {
+        LOG_RPC_DETAIL("Received %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str());
+    }
+
+    return true;
+}
+
+sp<IBinder> RpcState::getRootObject(const base::unique_fd& fd,
+                                    const sp<RpcConnection>& connection) {
+    Parcel data;
+    data.markForRpc(connection);
+    Parcel reply;
+
+    status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT, data,
+                               connection, &reply, 0);
+    if (status != OK) {
+        ALOGE("Error getting root object: %s", statusToString(status).c_str());
+        return nullptr;
+    }
+
+    return reply.readStrongBinder();
+}
+
+status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address, uint32_t code,
+                            const Parcel& data, const sp<RpcConnection>& connection, Parcel* reply,
+                            uint32_t flags) {
+    uint64_t asyncNumber = 0;
+
+    if (!address.isZero()) {
+        std::lock_guard<std::mutex> _l(mNodeMutex);
+        if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
+        auto it = mNodeForAddress.find(address);
+        LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending transact on unknown address %s",
+                            address.toString().c_str());
+
+        if (flags & IBinder::FLAG_ONEWAY) {
+            asyncNumber = it->second.asyncNumber++;
+        }
+    }
+
+    if (!data.isForRpc()) {
+        ALOGE("Refusing to send RPC with parcel not crafted for RPC");
+        return BAD_TYPE;
+    }
+
+    if (data.objectsCount() != 0) {
+        ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data);
+        return BAD_TYPE;
+    }
+
+    RpcWireTransaction transaction{
+            .address = address.viewRawEmbedded(),
+            .code = code,
+            .flags = flags,
+            .asyncNumber = asyncNumber,
+    };
+
+    std::vector<uint8_t> transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+    memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction));
+    memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize());
+
+    if (transactionData.size() > std::numeric_limits<uint32_t>::max()) {
+        ALOGE("Transaction size too big %zu", transactionData.size());
+        return BAD_VALUE;
+    }
+
+    RpcWireHeader command{
+            .command = RPC_COMMAND_TRANSACT,
+            .bodySize = static_cast<uint32_t>(transactionData.size()),
+    };
+
+    if (!rpcSend(fd, "transact header", &command, sizeof(command))) {
+        return DEAD_OBJECT;
+    }
+    if (!rpcSend(fd, "command body", transactionData.data(), transactionData.size())) {
+        return DEAD_OBJECT;
+    }
+
+    if (flags & IBinder::FLAG_ONEWAY) {
+        return OK; // do not wait for result
+    }
+
+    LOG_ALWAYS_FATAL_IF(reply == nullptr, "Reply parcel must be used for synchronous transaction.");
+
+    return waitForReply(fd, connection, reply);
+}
+
+static void cleanup_data(Parcel* p, const uint8_t* data, size_t dataSize,
+                         const binder_size_t* objects, size_t objectsCount) {
+    (void)p;
+    delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data));
+    (void)dataSize;
+    LOG_ALWAYS_FATAL_IF(objects != nullptr);
+    LOG_ALWAYS_FATAL_IF(objectsCount, 0);
+}
+
+status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+                                Parcel* reply) {
+    RpcWireHeader command;
+    while (true) {
+        if (!rpcRec(fd, "command header", &command, sizeof(command))) {
+            return DEAD_OBJECT;
+        }
+
+        if (command.command == RPC_COMMAND_REPLY) break;
+
+        status_t status = processServerCommand(fd, connection, command);
+        if (status != OK) return status;
+    }
+
+    uint8_t* data = new uint8_t[command.bodySize];
+
+    if (!rpcRec(fd, "reply body", data, command.bodySize)) {
+        return DEAD_OBJECT;
+    }
+
+    if (command.bodySize < sizeof(RpcWireReply)) {
+        ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireReply. Terminating!",
+              sizeof(RpcWireReply), command.bodySize);
+        terminate();
+        return BAD_VALUE;
+    }
+    RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data);
+    if (rpcReply->status != OK) return rpcReply->status;
+
+    reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
+                               nullptr, 0, cleanup_data);
+
+    reply->markForRpc(connection);
+
+    return OK;
+}
+
+status_t RpcState::sendDecStrong(const base::unique_fd& fd, const RpcAddress& addr) {
+    {
+        std::lock_guard<std::mutex> _l(mNodeMutex);
+        if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
+        auto it = mNodeForAddress.find(addr);
+        LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending dec strong on unknown address %s",
+                            addr.toString().c_str());
+        LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %s",
+                            addr.toString().c_str());
+
+        it->second.timesRecd--;
+        if (it->second.timesRecd == 0 && it->second.timesSent == 0) {
+            mNodeForAddress.erase(it);
+        }
+    }
+
+    RpcWireHeader cmd = {
+            .command = RPC_COMMAND_DEC_STRONG,
+            .bodySize = sizeof(RpcWireAddress),
+    };
+    if (!rpcSend(fd, "dec ref header", &cmd, sizeof(cmd))) return DEAD_OBJECT;
+    if (!rpcSend(fd, "dec ref body", &addr.viewRawEmbedded(), sizeof(RpcWireAddress)))
+        return DEAD_OBJECT;
+    return OK;
+}
+
+status_t RpcState::getAndExecuteCommand(const base::unique_fd& fd,
+                                        const sp<RpcConnection>& connection) {
+    LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", fd.get());
+
+    RpcWireHeader command;
+    if (!rpcRec(fd, "command header", &command, sizeof(command))) {
+        return DEAD_OBJECT;
+    }
+
+    return processServerCommand(fd, connection, command);
+}
+
+status_t RpcState::processServerCommand(const base::unique_fd& fd,
+                                        const sp<RpcConnection>& connection,
+                                        const RpcWireHeader& command) {
+    switch (command.command) {
+        case RPC_COMMAND_TRANSACT:
+            return processTransact(fd, connection, command);
+        case RPC_COMMAND_DEC_STRONG:
+            return processDecStrong(fd, command);
+    }
+
+    // We should always know the version of the opposing side, and since the
+    // RPC-binder-level wire protocol is not self synchronizing, we have no way
+    // to understand where the current command ends and the next one begins. We
+    // also can't consider it a fatal error because this would allow any client
+    // to kill us, so ending the connection for misbehaving client.
+    ALOGE("Unknown RPC command %d - terminating connection", command.command);
+    terminate();
+    return DEAD_OBJECT;
+}
+status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+                                   const RpcWireHeader& command) {
+    LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
+
+    std::vector<uint8_t> transactionData(command.bodySize);
+    if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) {
+        return DEAD_OBJECT;
+    }
+
+    return processTransactInternal(fd, connection, std::move(transactionData));
+}
+
+status_t RpcState::processTransactInternal(const base::unique_fd& fd,
+                                           const sp<RpcConnection>& connection,
+                                           std::vector<uint8_t>&& transactionData) {
+    if (transactionData.size() < sizeof(RpcWireTransaction)) {
+        ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
+              sizeof(RpcWireTransaction), transactionData.size());
+        terminate();
+        return BAD_VALUE;
+    }
+    RpcWireTransaction* transaction = reinterpret_cast<RpcWireTransaction*>(transactionData.data());
+
+    // TODO(b/182939933): heap allocation just for lookup in mNodeForAddress,
+    // maybe add an RpcAddress 'view' if the type remains 'heavy'
+    auto addr = RpcAddress::fromRawEmbedded(&transaction->address);
+
+    status_t replyStatus = OK;
+    sp<IBinder> target;
+    if (!addr.isZero()) {
+        std::lock_guard<std::mutex> _l(mNodeMutex);
+
+        auto it = mNodeForAddress.find(addr);
+        if (it == mNodeForAddress.end()) {
+            ALOGE("Unknown binder address %s.", addr.toString().c_str());
+            dump();
+            replyStatus = BAD_VALUE;
+        } else {
+            target = it->second.binder.promote();
+            if (target == nullptr) {
+                // This can happen if the binder is remote in this process, and
+                // another thread has called the last decStrong on this binder.
+                // However, for local binders, it indicates a misbehaving client
+                // (any binder which is being transacted on should be holding a
+                // strong ref count), so in either case, terminating the
+                // connection.
+                ALOGE("While transacting, binder has been deleted at address %s. Terminating!",
+                      addr.toString().c_str());
+                terminate();
+                replyStatus = BAD_VALUE;
+            } else if (target->localBinder() == nullptr) {
+                ALOGE("Transactions can only go to local binders, not address %s. Terminating!",
+                      addr.toString().c_str());
+                terminate();
+                replyStatus = BAD_VALUE;
+            } else if (transaction->flags & IBinder::FLAG_ONEWAY) {
+                if (transaction->asyncNumber != it->second.asyncNumber) {
+                    // we need to process some other asynchronous transaction
+                    // first
+                    // TODO(b/183140903): limit enqueues/detect overfill for bad client
+                    // TODO(b/183140903): detect when an object is deleted when it still has
+                    //        pending async transactions
+                    it->second.asyncTodo.push(BinderNode::AsyncTodo{
+                            .data = std::move(transactionData),
+                            .asyncNumber = transaction->asyncNumber,
+                    });
+                    LOG_RPC_DETAIL("Enqueuing %" PRId64 " on %s", transaction->asyncNumber,
+                                   addr.toString().c_str());
+                    return OK;
+                }
+            }
+        }
+    }
+
+    Parcel data;
+    data.setData(transaction->data, transactionData.size() - offsetof(RpcWireTransaction, data));
+    data.markForRpc(connection);
+
+    Parcel reply;
+    reply.markForRpc(connection);
+
+    if (replyStatus == OK) {
+        if (target) {
+            replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
+        } else {
+            LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
+            // special case for 'zero' address (special server commands)
+            switch (transaction->code) {
+                case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+                    sp<IBinder> root;
+                    sp<RpcServer> server = connection->server().promote();
+                    if (server) {
+                        root = server->getRootObject();
+                    } else {
+                        ALOGE("Root object requested, but no server attached.");
+                    }
+
+                    replyStatus = reply.writeStrongBinder(root);
+                    break;
+                }
+                default: {
+                    replyStatus = UNKNOWN_TRANSACTION;
+                }
+            }
+        }
+    }
+
+    if (transaction->flags & IBinder::FLAG_ONEWAY) {
+        if (replyStatus != OK) {
+            ALOGW("Oneway call failed with error: %d", replyStatus);
+        }
+
+        LOG_RPC_DETAIL("Processed async transaction %" PRId64 " on %s", transaction->asyncNumber,
+                       addr.toString().c_str());
+
+        // Check to see if there is another asynchronous transaction to process.
+        // This behavior differs from binder behavior, since in the binder
+        // driver, asynchronous transactions will be processed after existing
+        // pending binder transactions on the queue. The downside of this is
+        // that asynchronous transactions can be drowned out by synchronous
+        // transactions. However, we have no easy way to queue these
+        // transactions after the synchronous transactions we may want to read
+        // from the wire. So, in socket binder here, we have the opposite
+        // downside: asynchronous transactions may drown out synchronous
+        // transactions.
+        {
+            std::unique_lock<std::mutex> _l(mNodeMutex);
+            auto it = mNodeForAddress.find(addr);
+            // last refcount dropped after this transaction happened
+            if (it == mNodeForAddress.end()) return OK;
+
+            // note - only updated now, instead of later, so that other threads
+            // will queue any later transactions
+
+            // TODO(b/183140903): support > 2**64 async transactions
+            //     (we can do this by allowing asyncNumber to wrap, since we
+            //     don't expect more than 2**64 simultaneous transactions)
+            it->second.asyncNumber++;
+
+            if (it->second.asyncTodo.size() == 0) return OK;
+            if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
+                LOG_RPC_DETAIL("Found next async transaction %" PRId64 " on %s",
+                               it->second.asyncNumber, addr.toString().c_str());
+
+                // justification for const_cast (consider avoiding priority_queue):
+                // - AsyncTodo operator< doesn't depend on 'data' object
+                // - gotta go fast
+                std::vector<uint8_t> data = std::move(
+                        const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
+                it->second.asyncTodo.pop();
+                _l.unlock();
+                return processTransactInternal(fd, connection, std::move(data));
+            }
+        }
+        return OK;
+    }
+
+    RpcWireReply rpcReply{
+            .status = replyStatus,
+    };
+
+    std::vector<uint8_t> replyData(sizeof(RpcWireReply) + reply.dataSize());
+    memcpy(replyData.data() + 0, &rpcReply, sizeof(RpcWireReply));
+    memcpy(replyData.data() + sizeof(RpcWireReply), reply.data(), reply.dataSize());
+
+    if (replyData.size() > std::numeric_limits<uint32_t>::max()) {
+        ALOGE("Reply size too big %zu", transactionData.size());
+        terminate();
+        return BAD_VALUE;
+    }
+
+    RpcWireHeader cmdReply{
+            .command = RPC_COMMAND_REPLY,
+            .bodySize = static_cast<uint32_t>(replyData.size()),
+    };
+
+    if (!rpcSend(fd, "reply header", &cmdReply, sizeof(RpcWireHeader))) {
+        return DEAD_OBJECT;
+    }
+    if (!rpcSend(fd, "reply body", replyData.data(), replyData.size())) {
+        return DEAD_OBJECT;
+    }
+    return OK;
+}
+
+status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) {
+    LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
+
+    std::vector<uint8_t> commandData(command.bodySize);
+    if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) {
+        return DEAD_OBJECT;
+    }
+
+    if (command.bodySize < sizeof(RpcWireAddress)) {
+        ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
+              sizeof(RpcWireAddress), command.bodySize);
+        terminate();
+        return BAD_VALUE;
+    }
+    RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
+
+    // TODO(b/182939933): heap allocation just for lookup
+    auto addr = RpcAddress::fromRawEmbedded(address);
+    std::unique_lock<std::mutex> _l(mNodeMutex);
+    auto it = mNodeForAddress.find(addr);
+    if (it == mNodeForAddress.end()) {
+        ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
+        dump();
+        return OK;
+    }
+
+    sp<IBinder> target = it->second.binder.promote();
+    if (target == nullptr) {
+        ALOGE("While requesting dec strong, binder has been deleted at address %s. Terminating!",
+              addr.toString().c_str());
+        terminate();
+        return BAD_VALUE;
+    }
+
+    if (it->second.timesSent == 0) {
+        ALOGE("No record of sending binder, but requested decStrong: %s", addr.toString().c_str());
+        return OK;
+    }
+
+    LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %s",
+                        addr.toString().c_str());
+
+    sp<IBinder> tempHold;
+
+    it->second.timesSent--;
+    if (it->second.timesSent == 0) {
+        tempHold = it->second.sentRef;
+        it->second.sentRef = nullptr;
+
+        if (it->second.timesRecd == 0) {
+            mNodeForAddress.erase(it);
+        }
+    }
+
+    _l.unlock();
+    tempHold = nullptr; // destructor may make binder calls on this connection
+
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
new file mode 100644
index 0000000..f4f5151
--- /dev/null
+++ b/libs/binder/RpcState.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2020 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/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+#include <binder/RpcConnection.h>
+
+#include <map>
+#include <queue>
+
+namespace android {
+
+struct RpcWireHeader;
+
+/**
+ * Log a lot more information about RPC calls, when debugging issues. Usually,
+ * you would want to enable this in only one process. If repeated issues require
+ * a specific subset of logs to debug, this could be broken up like
+ * IPCThreadState's.
+ */
+#define SHOULD_LOG_RPC_DETAIL false
+
+#if SHOULD_LOG_RPC_DETAIL
+#define LOG_RPC_DETAIL(...) ALOGI(__VA_ARGS__)
+#else
+#define LOG_RPC_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
+#endif
+
+/**
+ * Abstracts away management of ref counts and the wire format from
+ * RpcConnection
+ */
+class RpcState {
+public:
+    RpcState();
+    ~RpcState();
+
+    sp<IBinder> getRootObject(const base::unique_fd& fd, const sp<RpcConnection>& connection);
+
+    [[nodiscard]] status_t transact(const base::unique_fd& fd, const RpcAddress& address,
+                                    uint32_t code, const Parcel& data,
+                                    const sp<RpcConnection>& connection, Parcel* reply,
+                                    uint32_t flags);
+    [[nodiscard]] status_t sendDecStrong(const base::unique_fd& fd, const RpcAddress& address);
+    [[nodiscard]] status_t getAndExecuteCommand(const base::unique_fd& fd,
+                                                const sp<RpcConnection>& connection);
+
+    /**
+     * Called by Parcel for outgoing binders. This implies one refcount of
+     * ownership to the outgoing binder.
+     */
+    [[nodiscard]] status_t onBinderLeaving(const sp<RpcConnection>& connection,
+                                           const sp<IBinder>& binder, RpcAddress* outAddress);
+
+    /**
+     * Called by Parcel for incoming binders. This either returns the refcount
+     * to the process, if this process already has one, or it takes ownership of
+     * that refcount
+     */
+    sp<IBinder> onBinderEntering(const sp<RpcConnection>& connection, const RpcAddress& address);
+
+    size_t countBinders();
+    void dump();
+
+private:
+    /**
+     * Called when reading or writing data to a connection fails to clean up
+     * data associated with the connection in order to cleanup binders.
+     * Specifically, we have a strong dependency cycle, since BpBinder is
+     * OBJECT_LIFETIME_WEAK (so that onAttemptIncStrong may return true).
+     *
+     *     BpBinder -> RpcConnection -> RpcState
+     *      ^-----------------------------/
+     *
+     * In the success case, eventually all refcounts should be propagated over
+     * the connection, though this could also be called to eagerly cleanup
+     * the connection.
+     *
+     * WARNING: RpcState is responsible for calling this when the connection is
+     * no longer recoverable.
+     */
+    void terminate();
+
+    [[nodiscard]] bool rpcSend(const base::unique_fd& fd, const char* what, const void* data,
+                               size_t size);
+    [[nodiscard]] bool rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size);
+
+    [[nodiscard]] status_t waitForReply(const base::unique_fd& fd,
+                                        const sp<RpcConnection>& connection, Parcel* reply);
+    [[nodiscard]] status_t processServerCommand(const base::unique_fd& fd,
+                                                const sp<RpcConnection>& connection,
+                                                const RpcWireHeader& command);
+    [[nodiscard]] status_t processTransact(const base::unique_fd& fd,
+                                           const sp<RpcConnection>& connection,
+                                           const RpcWireHeader& command);
+    [[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
+                                                   const sp<RpcConnection>& connection,
+                                                   std::vector<uint8_t>&& transactionData);
+    [[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
+                                            const RpcWireHeader& command);
+
+    struct BinderNode {
+        // Two cases:
+        // A - local binder we are serving
+        // B - remote binder, we are sending transactions to
+        wp<IBinder> binder;
+
+        // if timesSent > 0, this will be equal to binder.promote()
+        sp<IBinder> sentRef;
+
+        // Number of times we've sent this binder out of process, which
+        // translates to an implicit strong count. A client must send RPC binder
+        // socket's dec ref for each time it is sent out of process in order to
+        // deallocate it. Note, a proxy binder we are holding onto might be
+        // sent (this is important when the only remaining refcount of this
+        // binder is the one associated with a transaction sending it back to
+        // its server)
+        size_t timesSent = 0;
+
+        // Number of times we've received this binder, each time corresponds to
+        // a reference we hold over the wire (not a local incStrong/decStrong)
+        size_t timesRecd = 0;
+
+        // transaction ID, for async transactions
+        uint64_t asyncNumber = 0;
+
+        //
+        // CASE A - local binder we are serving
+        //
+
+        // async transaction queue, _only_ for local binder
+        struct AsyncTodo {
+            std::vector<uint8_t> data; // most convenient format, to move it here
+            uint64_t asyncNumber = 0;
+
+            bool operator<(const AsyncTodo& o) const {
+                return asyncNumber > /* !!! */ o.asyncNumber;
+            }
+        };
+        std::priority_queue<AsyncTodo> asyncTodo;
+
+        //
+        // CASE B - remote binder, we are sending transactions to
+        //
+
+        // (no additional data specific to remote binders)
+    };
+
+    std::mutex mNodeMutex;
+    bool mTerminated = false;
+    // binders known by both sides of a connection
+    std::map<RpcAddress, BinderNode> mNodeForAddress;
+};
+
+} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
new file mode 100644
index 0000000..60ec6c9
--- /dev/null
+++ b/libs/binder/RpcWireFormat.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 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
+
+namespace android {
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wpadded"
+
+enum : uint32_t {
+    /**
+     * follows is RpcWireTransaction, if flags != oneway, reply w/ RPC_COMMAND_REPLY expected
+     */
+    RPC_COMMAND_TRANSACT = 0,
+    /**
+     * follows is RpcWireReply
+     */
+    RPC_COMMAND_REPLY,
+    /**
+     * follows is RpcWireAddress
+     *
+     * note - this in the protocol directly instead of as a 'special
+     * transaction' in order to keep it as lightweight as possible (we don't
+     * want to create a 'Parcel' object for every decref)
+     */
+    RPC_COMMAND_DEC_STRONG,
+};
+
+/**
+ * These commands are used when the address in an RpcWireTransaction is zero'd
+ * out (no address). This allows the transact/reply flow to be used for
+ * additional server commands, without making the protocol for
+ * transactions/replies more complicated.
+ */
+enum : uint32_t {
+    RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
+};
+
+// serialization is like:
+// |RpcWireHeader|struct desginated by 'command'| (over and over again)
+
+struct RpcWireHeader {
+    uint32_t command; // RPC_COMMAND_*
+    uint32_t bodySize;
+
+    uint32_t reserved[2];
+};
+
+struct RpcWireAddress {
+    uint8_t address[32];
+};
+
+struct RpcWireTransaction {
+    RpcWireAddress address;
+    uint32_t code;
+    uint32_t flags;
+
+    uint64_t asyncNumber;
+
+    uint32_t reserved[4];
+
+    uint8_t data[0];
+};
+
+struct RpcWireReply {
+    int32_t status; // transact return
+    uint8_t data[0];
+};
+
+#pragma clang diagnostic pop
+
+} // namespace android
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index b56e09f..c3f1ba7 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -38,6 +38,18 @@
     };
 }
 
+void Stability::forceDowngradeCompilationUnit(const sp<IBinder>& binder) {
+    // Downgrading a remote binder would require also copying the version from
+    // the binder sent here. In practice though, we don't need to downgrade the
+    // stability of a remote binder, since this would as an effect only restrict
+    // what we can do to it.
+    LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder");
+
+    auto stability = Category::currentFromLevel(getLocalLevel());
+    status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE);
+    LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
 std::string Stability::Category::debugString() {
     return levelString(level) + " wire protocol version "
         + std::to_string(version);
@@ -45,13 +57,13 @@
 
 void Stability::markCompilationUnit(IBinder* binder) {
     auto stability = Category::currentFromLevel(getLocalLevel());
-    status_t result = setRepr(binder, stability.repr(), true /*log*/);
+    status_t result = setRepr(binder, stability.repr(), REPR_LOG);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 void Stability::markVintf(IBinder* binder) {
     auto stability = Category::currentFromLevel(Level::VINTF);
-    status_t result = setRepr(binder, stability.repr(), true /*log*/);
+    status_t result = setRepr(binder, stability.repr(), REPR_LOG);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
@@ -62,7 +74,7 @@
 
 void Stability::markVndk(IBinder* binder) {
     auto stability = Category::currentFromLevel(Level::VENDOR);
-    status_t result = setRepr(binder, stability.repr(), true /*log*/);
+    status_t result = setRepr(binder, stability.repr(), REPR_LOG);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
@@ -72,7 +84,7 @@
 
 void Stability::tryMarkCompilationUnit(IBinder* binder) {
     auto stability = Category::currentFromLevel(getLocalLevel());
-    (void) setRepr(binder, stability.repr(), false /*log*/);
+    (void) setRepr(binder, stability.repr(), REPR_NONE);
 }
 
 Stability::Level Stability::getLocalLevel() {
@@ -88,7 +100,10 @@
 #endif
 }
 
-status_t Stability::setRepr(IBinder* binder, int32_t representation, bool log) {
+status_t Stability::setRepr(IBinder* binder, int32_t representation, uint32_t flags) {
+    bool log = flags & REPR_LOG;
+    bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE;
+
     auto current = getCategory(binder);
     auto setting = Category::fromRepr(representation);
 
@@ -123,7 +138,11 @@
         return BAD_TYPE;
     }
 
-    if (current.repr() != 0 && current != setting) {
+    if (current == setting) return OK;
+
+    bool hasAlreadyBeenSet = current.repr() != 0;
+    bool isAllowedDowngrade = allowDowngrade && check(current, setting.level);
+    if (hasAlreadyBeenSet && !isAllowedDowngrade) {
         if (log) {
             ALOGE("Interface being set with %s but it is already marked as %s",
                   setting.debugString().c_str(),
@@ -132,7 +151,11 @@
         return BAD_TYPE;
     }
 
-    if (current == setting) return OK;
+    if (isAllowedDowngrade) {
+        ALOGI("Interface set with %s downgraded to %s stability",
+              current.debugString().c_str(),
+              setting.debugString().c_str());
+    }
 
     BBinder* local = binder->localBinder();
     if (local != nullptr) {
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 1fbaa13..7490b88 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -25,6 +25,9 @@
       "name": "binderLibTest"
     },
     {
+      "name": "binderRpcTest"
+    },
+    {
       "name": "binderStabilityTest"
     },
     {
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 22300ac..8ab7893 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,15 +17,19 @@
 #pragma once
 
 #include <binder/IBinder.h>
+#include <binder/RpcAddress.h>
 #include <utils/KeyedVector.h>
 #include <utils/Mutex.h>
 #include <utils/threads.h>
 
 #include <unordered_map>
+#include <variant>
 
 // ---------------------------------------------------------------------------
 namespace android {
 
+class RpcConnection;
+class RpcState;
 namespace internal {
 class Stability;
 }
@@ -37,6 +41,14 @@
 {
 public:
     static BpBinder*    create(int32_t handle);
+    static BpBinder* create(const sp<RpcConnection>& connection, const RpcAddress& address);
+
+    /**
+     * Return value:
+     * true - this is associated with a socket RpcConnection
+     * false - (usual) binder over e.g. /dev/binder
+     */
+    bool isRpcBinder() const;
 
     virtual const String16&    getInterfaceDescriptor() const;
     virtual bool        isBinderAlive() const;
@@ -108,33 +120,56 @@
         KeyedVector<const void*, entry_t> mObjects;
     };
 
-    class PrivateAccessorForHandle {
+    class PrivateAccessorForId {
     private:
-        friend BpBinder;
-        friend ::android::Parcel;
-        friend ::android::ProcessState;
-        explicit PrivateAccessorForHandle(const BpBinder* binder) : mBinder(binder) {}
-        int32_t handle() const { return mBinder->handle(); }
+        friend class BpBinder;
+        friend class ::android::Parcel;
+        friend class ::android::ProcessState;
+        friend class ::android::RpcState;
+        explicit PrivateAccessorForId(const BpBinder* binder) : mBinder(binder) {}
+
+        // valid if !isRpcBinder
+        int32_t binderHandle() const { return mBinder->binderHandle(); }
+
+        // valid if isRpcBinder
+        const RpcAddress& rpcAddress() const { return mBinder->rpcAddress(); }
+        const sp<RpcConnection>& rpcConnection() const { return mBinder->rpcConnection(); }
+
         const BpBinder* mBinder;
     };
-    const PrivateAccessorForHandle getPrivateAccessorForHandle() const {
-        return PrivateAccessorForHandle(this);
+    const PrivateAccessorForId getPrivateAccessorForId() const {
+        return PrivateAccessorForId(this);
     }
 
 private:
-    friend PrivateAccessorForHandle;
+    friend PrivateAccessorForId;
 
-    int32_t             handle() const;
-                        BpBinder(int32_t handle,int32_t trackedUid);
+    struct BinderHandle {
+        int32_t handle;
+    };
+    struct SocketHandle {
+        sp<RpcConnection> connection;
+        RpcAddress address;
+    };
+    using Handle = std::variant<BinderHandle, SocketHandle>;
+
+    int32_t binderHandle() const;
+    const RpcAddress& rpcAddress() const;
+    const sp<RpcConnection>& rpcConnection() const;
+
+    explicit BpBinder(Handle&& handle);
+    BpBinder(BinderHandle&& handle, int32_t trackedUid);
+    explicit BpBinder(SocketHandle&& handle);
+
     virtual             ~BpBinder();
     virtual void        onFirstRef();
     virtual void        onLastStrongRef(const void* id);
     virtual bool        onIncStrongAttempted(uint32_t flags, const void* id);
 
     friend ::android::internal::Stability;
-            int32_t             mStability;
 
-    const   int32_t             mHandle;
+    int32_t mStability;
+    Handle mHandle;
 
     struct Obituary {
         wp<DeathRecipient> recipient;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 7b298f5..9578372 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -50,11 +50,14 @@
 class IBinder;
 class IPCThreadState;
 class ProcessState;
+class RpcConnection;
 class String8;
 class TextOutput;
 
 class Parcel {
     friend class IPCThreadState;
+    friend class RpcState;
+
 public:
     class ReadableBlob;
     class WritableBlob;
@@ -92,7 +95,21 @@
     // In order to verify this, heap dumps should be used.
     void                markSensitive() const;
 
-    // Writes the RPC header.
+    // For a 'data' Parcel, this should mark the Parcel as being prepared for a
+    // transaction on this specific binder object. Based on this, the format of
+    // the wire binder protocol may change (data is written differently when it
+    // is for an RPC transaction).
+    void markForBinder(const sp<IBinder>& binder);
+
+    // Whenever possible, markForBinder should be preferred. This method is
+    // called automatically on reply Parcels for RPC transactions.
+    void markForRpc(const sp<RpcConnection>& connection);
+
+    // Whether this Parcel is written for RPC transactions (after calls to
+    // markForBinder or markForRpc).
+    bool isForRpc() const;
+
+    // Writes the IPC/RPC header.
     status_t            writeInterfaceToken(const String16& interface);
     status_t            writeInterfaceToken(const char16_t* str, size_t len);
 
@@ -1106,6 +1123,7 @@
     mutable bool        mObjectsSorted;
 
     mutable bool        mRequestHeaderPresent;
+
     mutable size_t      mWorkSourceRequestHeaderPosition;
 
     mutable bool        mFdsKnown;
@@ -1118,8 +1136,7 @@
 
     release_func        mOwner;
 
-    // TODO(167966510): reserved for binder/version/stability
-    void*               mReserved = reinterpret_cast<void*>(0xAAAAAAAA);
+    sp<RpcConnection> mConnection;
 
     class Blob {
     public:
diff --git a/libs/binder/include/binder/RpcAddress.h b/libs/binder/include/binder/RpcAddress.h
new file mode 100644
index 0000000..5a3f3a6
--- /dev/null
+++ b/libs/binder/include/binder/RpcAddress.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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 <memory>
+
+#include <utils/Errors.h>
+
+// WARNING: This is a feature which is still in development, and it is subject
+// to radical change. Any production use of this may subject your code to any
+// number of problems.
+
+namespace android {
+
+class Parcel;
+struct RpcWireAddress;
+
+/**
+ * This class represents an identifier of a binder object.
+ *
+ * The purpose of this class it to hide the ABI of an RpcWireAddress, and
+ * potentially allow us to change the size of it in the future (RpcWireAddress
+ * is PIMPL, essentially - although the type that is used here is not exposed).
+ */
+class RpcAddress {
+public:
+    /**
+     * The zero address is used for special RPC transactions, but it might also
+     * be used in conjunction with readFromParcel.
+     */
+    static RpcAddress zero();
+
+    bool isZero() const;
+
+    /**
+     * Create a new address which is unique
+     */
+    static RpcAddress unique();
+
+    /**
+     * Creates a new address as a copy of an embedded object.
+     */
+    static RpcAddress fromRawEmbedded(const RpcWireAddress* raw);
+    const RpcWireAddress& viewRawEmbedded() const;
+
+    bool operator<(const RpcAddress& rhs) const;
+    std::string toString() const;
+
+    status_t writeToParcel(Parcel* parcel) const;
+    status_t readFromParcel(const Parcel& parcel);
+
+    ~RpcAddress();
+
+private:
+    RpcAddress();
+
+    std::shared_ptr<RpcWireAddress> mRawAddr;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
new file mode 100644
index 0000000..65c5232
--- /dev/null
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2020 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/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/RpcAddress.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <optional>
+#include <vector>
+
+// WARNING: This is a feature which is still in development, and it is subject
+// to radical change. Any production use of this may subject your code to any
+// number of problems.
+
+namespace android {
+
+class Parcel;
+class RpcServer;
+class RpcState;
+
+/**
+ * This represents a multi-threaded/multi-socket connection between a client
+ * and a server.
+ */
+class RpcConnection final : public virtual RefBase {
+public:
+    static sp<RpcConnection> make();
+
+    /**
+     * This represents a connection for responses, e.g.:
+     *
+     *     process A serves binder a
+     *     process B opens a connection to process A
+     *     process B makes binder b and sends it to A
+     *     A uses this 'back connection' to send things back to B
+     *
+     * This should be called once, and then a call should be made to join per
+     * connection thread.
+     */
+    [[nodiscard]] bool setupUnixDomainServer(const char* path);
+
+    /**
+     * This should be called once per thread, matching 'join' in the remote
+     * process.
+     */
+    [[nodiscard]] bool addUnixDomainClient(const char* path);
+
+    /**
+     * Query the other side of the connection for the root object hosted by that
+     * process's RpcServer (if one exists)
+     */
+    sp<IBinder> getRootObject();
+
+    [[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
+                                    Parcel* reply, uint32_t flags);
+    [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
+
+    /**
+     * Adds a server thread accepting connections. Must be called after
+     * setup*Server.
+     */
+    void join();
+
+    ~RpcConnection();
+
+    void setForServer(const wp<RpcServer>& server);
+    wp<RpcServer> server();
+
+    // internal only
+    const std::unique_ptr<RpcState>& state() { return mState; }
+
+private:
+    RpcConnection();
+
+    void addServer(base::unique_fd&& fd);
+    void addClient(base::unique_fd&& fd);
+
+    struct ConnectionSocket : public RefBase {
+        base::unique_fd fd;
+
+        // whether this or another thread is currently using this fd to make
+        // or receive transactions.
+        std::optional<pid_t> exclusiveTid;
+    };
+
+    enum class SocketUse {
+        CLIENT,
+        CLIENT_ASYNC,
+        CLIENT_REFCOUNT,
+        SERVER,
+    };
+
+    // RAII object for connection socket
+    class ExclusiveSocket {
+    public:
+        explicit ExclusiveSocket(const sp<RpcConnection>& connection, SocketUse use);
+        ~ExclusiveSocket();
+        const base::unique_fd& fd() { return mSocket->fd; }
+
+    private:
+        static void findSocket(pid_t tid, sp<ConnectionSocket>* exclusive,
+                               sp<ConnectionSocket>* available,
+                               std::vector<sp<ConnectionSocket>>& sockets, size_t socketsIndexHint);
+
+        sp<RpcConnection> mConnection; // avoid deallocation
+        sp<ConnectionSocket> mSocket;
+
+        // whether this is being used for a nested transaction (being on the same
+        // thread guarantees we won't write in the middle of a message, the way
+        // the wire protocol is constructed guarantees this is safe).
+        bool mReentrant = false;
+    };
+
+    // On the other side of a connection, for each of mClients here, there should
+    // be one of mServers on the other side (and vice versa).
+    //
+    // For the simplest connection, a single server with one client, you would
+    // have:
+    //  - the server has a single 'mServers' and a thread listening on this
+    //  - the client has a single 'mClients' and makes calls to this
+    //  - here, when the client makes a call, the server can call back into it
+    //    (nested calls), but outside of this, the client will only ever read
+    //    calls from the server when it makes a call itself.
+    //
+    // For a more complicated case, the client might itself open up a thread to
+    // serve calls to the server at all times (e.g. if it hosts a callback)
+
+    wp<RpcServer> mForServer; // maybe null, for client connections
+
+    std::unique_ptr<RpcState> mState;
+
+    base::unique_fd mServer; // socket we are accepting connections on
+
+    std::mutex mSocketMutex;           // for all below
+    std::condition_variable mSocketCv; // for mWaitingThreads
+    size_t mWaitingThreads = 0;
+    size_t mClientsOffset = 0; // hint index into clients, ++ when sending an async transaction
+    std::vector<sp<ConnectionSocket>> mClients;
+    std::vector<sp<ConnectionSocket>> mServers;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
new file mode 100644
index 0000000..a2c2aee
--- /dev/null
+++ b/libs/binder/include/binder/RpcServer.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 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/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/RpcConnection.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+// WARNING: This is a feature which is still in development, and it is subject
+// to radical change. Any production use of this may subject your code to any
+// number of problems.
+
+namespace android {
+
+/**
+ * This represents a server of an interface, which may be connected to by any
+ * number of clients over sockets.
+ *
+ * This object is not (currently) thread safe. All calls to it are expected to
+ * happen at process startup.
+ */
+class RpcServer final : public virtual RefBase {
+public:
+    static sp<RpcServer> make();
+
+    void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+    /**
+     * Setup a static connection, when the number of clients are known.
+     *
+     * Each call to this function corresponds to a different client, and clients
+     * each have their own threadpools.
+     *
+     * TODO(b/167966510): support dynamic creation of connections/threads
+     */
+    sp<RpcConnection> addClientConnection();
+
+    /**
+     * Allowing a server to explicitly drop clients would be easy to add here,
+     * but it is not currently implemented, since users of this functionality
+     * could not use similar functionality if they are running under real
+     * binder.
+     */
+    // void drop(const sp<RpcConnection>& connection);
+
+    /**
+     * The root object can be retrieved by any client, without any
+     * authentication.
+     */
+    void setRootObject(const sp<IBinder>& binder);
+
+    /**
+     * Root object set with setRootObject
+     */
+    sp<IBinder> getRootObject();
+
+    ~RpcServer();
+
+private:
+    RpcServer();
+
+    bool mAgreedExperimental = false;
+
+    sp<IBinder> mRootObject;
+
+    std::vector<sp<RpcConnection>> mConnections; // per-client
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 12272ba..a09e587 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -49,10 +49,17 @@
 // that it knows how to process. The summary of stability of a binder is
 // represented by a Stability::Category object.
 
-// WARNING: These APIs are only ever expected to be called by auto-generated code.
-//     Instead of calling them, you should set the stability of a .aidl interface
 class Stability final {
 public:
+    // Given a binder interface at a certain stability, there may be some
+    // requirements associated with that higher stability level. For instance, a
+    // VINTF stability binder is required to be in the VINTF manifest. This API
+    // can be called to use that same interface within a partition.
+    static void forceDowngradeCompilationUnit(const sp<IBinder>& binder);
+
+    // WARNING: Below APIs are only ever expected to be called by auto-generated code.
+    //     Instead of calling them, you should set the stability of a .aidl interface
+
     // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
     // change or modify the stability class of the interface you are using.
     // This must be called as soon as the binder in question is constructed. No thread safety
@@ -139,9 +146,14 @@
     // returns the stability according to how this was built
     static Level getLocalLevel();
 
+    enum {
+      REPR_NONE = 0,
+      REPR_LOG = 1,
+      REPR_ALLOW_DOWNGRADE = 2,
+    };
     // applies stability to binder if stability level is known
     __attribute__((warn_unused_result))
-    static status_t setRepr(IBinder* binder, int32_t representation, bool log);
+    static status_t setRepr(IBinder* binder, int32_t representation, uint32_t flags);
 
     // get stability information as encoded on the wire
     static Category getCategory(IBinder* binder);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 3bbb0b5..a44cddf 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -105,6 +105,26 @@
 }
 
 cc_test {
+    name: "binderRpcTest",
+    defaults: ["binder_test_defaults"],
+
+    srcs: [
+        "IBinderRpcSession.aidl",
+        "IBinderRpcTest.aidl",
+        "binderRpcTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "libutils",
+        "libcutils",
+        "liblog",
+    ],
+    test_suites: ["general-tests"],
+    require_root: true,
+}
+
+cc_test {
     name: "binderThroughputTest",
     defaults: ["binder_test_defaults"],
     srcs: ["binderThroughputTest.cpp"],
diff --git a/libs/binder/tests/IBinderRpcSession.aidl b/libs/binder/tests/IBinderRpcSession.aidl
new file mode 100644
index 0000000..cf5f318
--- /dev/null
+++ b/libs/binder/tests/IBinderRpcSession.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+interface IBinderRpcSession {
+    @utf8InCpp String getName();
+}
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
new file mode 100644
index 0000000..2bdb264
--- /dev/null
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+interface IBinderRpcTest {
+    oneway void sendString(@utf8InCpp String str);
+    @utf8InCpp String doubleString(@utf8InCpp String str);
+
+    // number of known RPC binders to process, RpcState::countBinders
+    int countBinders();
+
+    // Caller sends server, callee pings caller's server and returns error code.
+    int pingMe(IBinder binder);
+    @nullable IBinder repeatBinder(@nullable IBinder binder);
+
+    void holdBinder(@nullable IBinder binder);
+    @nullable IBinder getHeldBinder();
+
+    // Idea is client creates its own instance of IBinderRpcTest and calls this,
+    // and the server calls 'binder' with (calls - 1) passing itself as 'binder',
+    // going back and forth until calls = 0
+    void nestMe(IBinderRpcTest binder, int calls);
+
+    // should always return the same binder
+    IBinder alwaysGiveMeTheSameBinder();
+
+    // Idea is that the server will not hold onto the session, the remote connection
+    // object must. This is to test lifetimes of binder objects, and consequently, also
+    // identity (since by assigning sessions names, we can make sure a section always
+    // references the session it was originally opened with).
+    IBinderRpcSession openSession(@utf8InCpp String name);
+
+    // Decremented in ~IBinderRpcSession
+    int getNumOpenSessions();
+
+    // primitives to test threading behavior
+    void lock();
+    oneway void unlockInMsAsync(int ms);
+    void lockUnlock(); // locks and unlocks a mutex
+
+    // take up binder thread for some time
+    void sleepMs(int ms);
+    oneway void sleepMsAsync(int ms);
+
+    void die(boolean cleanup);
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
new file mode 100644
index 0000000..6fa5333
--- /dev/null
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -0,0 +1,762 @@
+/*
+ * Copyright (C) 2020 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 <sys/prctl.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <iostream>
+#include <thread>
+
+#include <BnBinderRpcSession.h>
+#include <BnBinderRpcTest.h>
+#include <android-base/logging.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcConnection.h>
+#include <binder/RpcServer.h>
+#include <gtest/gtest.h>
+
+#include "../RpcState.h" // for debugging
+
+namespace android {
+
+using android::binder::Status;
+
+#define EXPECT_OK(status)                 \
+    do {                                  \
+        Status stat = (status);           \
+        EXPECT_TRUE(stat.isOk()) << stat; \
+    } while (false)
+
+class MyBinderRpcSession : public BnBinderRpcSession {
+public:
+    static std::atomic<int32_t> gNum;
+
+    MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
+    Status getName(std::string* name) override {
+        *name = mName;
+        return Status::ok();
+    }
+    ~MyBinderRpcSession() { gNum--; }
+
+private:
+    std::string mName;
+};
+std::atomic<int32_t> MyBinderRpcSession::gNum;
+
+class MyBinderRpcTest : public BnBinderRpcTest {
+public:
+    sp<RpcConnection> connection;
+
+    Status sendString(const std::string& str) override {
+        std::cout << "Child received string: " << str << std::endl;
+        return Status::ok();
+    }
+    Status doubleString(const std::string& str, std::string* strstr) override {
+        std::cout << "Child received string to double: " << str << std::endl;
+        *strstr = str + str;
+        return Status::ok();
+    }
+    Status countBinders(int32_t* out) override {
+        if (connection == nullptr) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        *out = connection->state()->countBinders();
+        if (*out != 1) {
+            connection->state()->dump();
+        }
+        return Status::ok();
+    }
+    Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
+        if (binder == nullptr) {
+            std::cout << "Received null binder!" << std::endl;
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        *out = binder->pingBinder();
+        return Status::ok();
+    }
+    Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+        *out = binder;
+        return Status::ok();
+    }
+    static sp<IBinder> mHeldBinder;
+    Status holdBinder(const sp<IBinder>& binder) override {
+        mHeldBinder = binder;
+        return Status::ok();
+    }
+    Status getHeldBinder(sp<IBinder>* held) override {
+        *held = mHeldBinder;
+        return Status::ok();
+    }
+    Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
+        if (count <= 0) return Status::ok();
+        return binder->nestMe(this, count - 1);
+    }
+    Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
+        static sp<IBinder> binder = new BBinder;
+        *out = binder;
+        return Status::ok();
+    }
+    Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
+        *out = new MyBinderRpcSession(name);
+        return Status::ok();
+    }
+    Status getNumOpenSessions(int32_t* out) override {
+        *out = MyBinderRpcSession::gNum;
+        return Status::ok();
+    }
+
+    std::mutex blockMutex;
+    Status lock() override {
+        blockMutex.lock();
+        return Status::ok();
+    }
+    Status unlockInMsAsync(int32_t ms) override {
+        usleep(ms * 1000);
+        blockMutex.unlock();
+        return Status::ok();
+    }
+    Status lockUnlock() override {
+        std::lock_guard<std::mutex> _l(blockMutex);
+        return Status::ok();
+    }
+
+    Status sleepMs(int32_t ms) override {
+        usleep(ms * 1000);
+        return Status::ok();
+    }
+
+    Status sleepMsAsync(int32_t ms) override {
+        // In-process binder calls are asynchronous, but the call to this method
+        // is synchronous wrt its client. This in/out-process threading model
+        // diffentiation is a classic binder leaky abstraction (for better or
+        // worse) and is preserved here the way binder sockets plugs itself
+        // into BpBinder, as nothing is changed at the higher levels
+        // (IInterface) which result in this behavior.
+        return sleepMs(ms);
+    }
+
+    Status die(bool cleanup) override {
+        if (cleanup) {
+            exit(1);
+        } else {
+            _exit(1);
+        }
+    }
+};
+sp<IBinder> MyBinderRpcTest::mHeldBinder;
+
+class Process {
+public:
+    Process(const std::function<void()>& f) {
+        if (0 == (mPid = fork())) {
+            // racey: assume parent doesn't crash before this is set
+            prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+            f();
+        }
+    }
+    ~Process() {
+        if (mPid != 0) {
+            kill(mPid, SIGKILL);
+        }
+    }
+
+private:
+    pid_t mPid = 0;
+};
+
+static std::string allocateSocketAddress() {
+    static size_t id = 0;
+
+    return "/dev/binderRpcTest_" + std::to_string(id++);
+};
+
+struct ProcessConnection {
+    // reference to process hosting a socket server
+    Process host;
+
+    // client connection object associated with other process
+    sp<RpcConnection> connection;
+
+    // pre-fetched root object
+    sp<IBinder> rootBinder;
+
+    // whether connection should be invalidated by end of run
+    bool expectInvalid = false;
+
+    ~ProcessConnection() {
+        rootBinder = nullptr;
+        EXPECT_NE(nullptr, connection);
+        EXPECT_NE(nullptr, connection->state());
+        EXPECT_EQ(0, connection->state()->countBinders()) << (connection->state()->dump(), "dump:");
+
+        wp<RpcConnection> weakConnection = connection;
+        connection = nullptr;
+        EXPECT_EQ(nullptr, weakConnection.promote()) << "Leaked connection";
+    }
+};
+
+// This creates a new process serving an interface on a certain number of
+// threads.
+ProcessConnection createRpcTestSocketServerProcess(
+        size_t numThreads,
+        const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
+    CHECK_GT(numThreads, 0);
+
+    std::string addr = allocateSocketAddress();
+    unlink(addr.c_str());
+
+    auto ret = ProcessConnection{
+            .host = Process([&] {
+                sp<RpcServer> server = RpcServer::make();
+
+                server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+
+                // server supporting one client on one socket
+                sp<RpcConnection> connection = server->addClientConnection();
+                CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
+
+                configure(server, connection);
+
+                // accept 'numThreads' connections
+                std::vector<std::thread> pool;
+                for (size_t i = 0; i + 1 < numThreads; i++) {
+                    pool.push_back(std::thread([=] { connection->join(); }));
+                }
+                connection->join();
+                for (auto& t : pool) t.join();
+            }),
+            .connection = RpcConnection::make(),
+    };
+
+    // wait up to 1s for sockets to be created
+    constexpr useconds_t kMaxWaitUs = 1000000;
+    constexpr useconds_t kWaitDivision = 100;
+    for (size_t i = 0; i < kWaitDivision && 0 != access(addr.c_str(), F_OK); i++) {
+        usleep(kMaxWaitUs / kWaitDivision);
+    }
+
+    // create remainder of connections
+    for (size_t i = 0; i < numThreads; i++) {
+        // Connection refused sometimes after file created but before listening.
+        CHECK(ret.connection->addUnixDomainClient(addr.c_str()) ||
+              (usleep(10000), ret.connection->addUnixDomainClient(addr.c_str())))
+                << i;
+    }
+
+    ret.rootBinder = ret.connection->getRootObject();
+    return ret;
+}
+
+// Process connection where the process hosts IBinderRpcTest, the server used
+// for most testing here
+struct BinderRpcTestProcessConnection {
+    ProcessConnection proc;
+
+    // pre-fetched root object
+    sp<IBinder> rootBinder;
+
+    // pre-casted root object
+    sp<IBinderRpcTest> rootIface;
+
+    ~BinderRpcTestProcessConnection() {
+        if (!proc.expectInvalid) {
+            int32_t remoteBinders = 0;
+            EXPECT_OK(rootIface->countBinders(&remoteBinders));
+            // should only be the root binder object, iface
+            EXPECT_EQ(remoteBinders, 1);
+        }
+
+        rootIface = nullptr;
+        rootBinder = nullptr;
+    }
+};
+
+BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
+    BinderRpcTestProcessConnection ret{
+            .proc = createRpcTestSocketServerProcess(numThreads,
+                                                     [&](const sp<RpcServer>& server,
+                                                         const sp<RpcConnection>& connection) {
+                                                         sp<MyBinderRpcTest> service =
+                                                                 new MyBinderRpcTest;
+                                                         server->setRootObject(service);
+                                                         service->connection =
+                                                                 connection; // for testing only
+                                                     }),
+    };
+
+    ret.rootBinder = ret.proc.rootBinder;
+    ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
+
+    return ret;
+}
+
+TEST(BinderRpc, RootObjectIsNull) {
+    auto proc = createRpcTestSocketServerProcess(1,
+                                                 [](const sp<RpcServer>& server,
+                                                    const sp<RpcConnection>&) {
+                                                     // this is the default, but to be explicit
+                                                     server->setRootObject(nullptr);
+                                                 });
+
+    // retrieved by getRootObject when process is created above
+    EXPECT_EQ(nullptr, proc.rootBinder);
+
+    // make sure we can retrieve it again (process doesn't crash)
+    EXPECT_EQ(nullptr, proc.connection->getRootObject());
+}
+
+TEST(BinderRpc, Ping) {
+    auto proc = createRpcTestSocketServerProcess(1);
+    ASSERT_NE(proc.rootBinder, nullptr);
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+TEST(BinderRpc, TransactionsMustBeMarkedRpc) {
+    auto proc = createRpcTestSocketServerProcess(1);
+    Parcel data;
+    Parcel reply;
+    EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
+}
+
+TEST(BinderRpc, UnknownTransaction) {
+    auto proc = createRpcTestSocketServerProcess(1);
+    Parcel data;
+    data.markForBinder(proc.rootBinder);
+    Parcel reply;
+    EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0));
+}
+
+TEST(BinderRpc, SendSomethingOneway) {
+    auto proc = createRpcTestSocketServerProcess(1);
+    EXPECT_OK(proc.rootIface->sendString("asdf"));
+}
+
+TEST(BinderRpc, SendAndGetResultBack) {
+    auto proc = createRpcTestSocketServerProcess(1);
+    std::string doubled;
+    EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
+    EXPECT_EQ("cool cool ", doubled);
+}
+
+TEST(BinderRpc, SendAndGetResultBackBig) {
+    auto proc = createRpcTestSocketServerProcess(1);
+    std::string single = std::string(1024, 'a');
+    std::string doubled;
+    EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
+    EXPECT_EQ(single + single, doubled);
+}
+
+TEST(BinderRpc, CallMeBack) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    int32_t pingResult;
+    EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
+    EXPECT_EQ(OK, pingResult);
+
+    EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST(BinderRpc, RepeatBinder) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> inBinder = new MyBinderRpcSession("foo");
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+    EXPECT_EQ(inBinder, outBinder);
+
+    wp<IBinder> weak = inBinder;
+    inBinder = nullptr;
+    outBinder = nullptr;
+
+    // Force reading a reply, to process any pending dec refs from the other
+    // process (the other process will process dec refs there before processing
+    // the ping here).
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    EXPECT_EQ(nullptr, weak.promote());
+
+    EXPECT_EQ(0, MyBinderRpcSession::gNum);
+}
+
+TEST(BinderRpc, RepeatTheirBinder) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinderRpcSession> session;
+    EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+
+    sp<IBinder> inBinder = IInterface::asBinder(session);
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(inBinder, &outBinder));
+    EXPECT_EQ(inBinder, outBinder);
+
+    wp<IBinder> weak = inBinder;
+    session = nullptr;
+    inBinder = nullptr;
+    outBinder = nullptr;
+
+    // Force reading a reply, to process any pending dec refs from the other
+    // process (the other process will process dec refs there before processing
+    // the ping here).
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST(BinderRpc, RepeatBinderNull) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
+    EXPECT_EQ(nullptr, outBinder);
+}
+
+TEST(BinderRpc, HoldBinder) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    IBinder* ptr = nullptr;
+    {
+        sp<IBinder> binder = new BBinder();
+        ptr = binder.get();
+        EXPECT_OK(proc.rootIface->holdBinder(binder));
+    }
+
+    sp<IBinder> held;
+    EXPECT_OK(proc.rootIface->getHeldBinder(&held));
+
+    EXPECT_EQ(held.get(), ptr);
+
+    // stop holding binder, because we test to make sure references are cleaned
+    // up
+    EXPECT_OK(proc.rootIface->holdBinder(nullptr));
+    // and flush ref counts
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+}
+
+// START TESTS FOR LIMITATIONS OF SOCKET BINDER
+// These are behavioral differences form regular binder, where certain usecases
+// aren't supported.
+
+TEST(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) {
+    auto proc1 = createRpcTestSocketServerProcess(1);
+    auto proc2 = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> outBinder;
+    EXPECT_EQ(INVALID_OPERATION,
+              proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
+}
+
+TEST(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+    sp<IBinder> outBinder;
+    EXPECT_EQ(INVALID_OPERATION,
+              proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
+}
+
+TEST(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    // for historical reasons, IServiceManager interface only returns the
+    // exception code
+    EXPECT_EQ(binder::Status::EX_TRANSACTION_FAILED,
+              defaultServiceManager()->addService(String16("not_suspicious"), proc.rootBinder));
+}
+
+// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+
+TEST(BinderRpc, RepeatRootObject) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> outBinder;
+    EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
+    EXPECT_EQ(proc.rootBinder, outBinder);
+}
+
+TEST(BinderRpc, NestedTransactions) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    auto nastyNester = sp<MyBinderRpcTest>::make();
+    EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
+
+    wp<IBinder> weak = nastyNester;
+    nastyNester = nullptr;
+    EXPECT_EQ(nullptr, weak.promote());
+}
+
+TEST(BinderRpc, SameBinderEquality) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> a;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+
+    sp<IBinder> b;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+    EXPECT_EQ(a, b);
+}
+
+TEST(BinderRpc, SameBinderEqualityWeak) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinder> a;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+    wp<IBinder> weak = a;
+    a = nullptr;
+
+    sp<IBinder> b;
+    EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&b));
+
+    // this is the wrong behavior, since BpBinder
+    // doesn't implement onIncStrongAttempted
+    // but make sure there is no crash
+    EXPECT_EQ(nullptr, weak.promote());
+
+    GTEST_SKIP() << "Weak binders aren't currently re-promotable for RPC binder.";
+
+    // In order to fix this:
+    // - need to have incStrongAttempted reflected across IPC boundary (wait for
+    //   response to promote - round trip...)
+    // - sendOnLastWeakRef, to delete entries out of RpcState table
+    EXPECT_EQ(b, weak.promote());
+}
+
+#define expectSessions(expected, iface)                   \
+    do {                                                  \
+        int session;                                      \
+        EXPECT_OK((iface)->getNumOpenSessions(&session)); \
+        EXPECT_EQ(expected, session);                     \
+    } while (false)
+
+TEST(BinderRpc, SingleSession) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    sp<IBinderRpcSession> session;
+    EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
+    std::string out;
+    EXPECT_OK(session->getName(&out));
+    EXPECT_EQ("aoeu", out);
+
+    expectSessions(1, proc.rootIface);
+    session = nullptr;
+    expectSessions(0, proc.rootIface);
+}
+
+TEST(BinderRpc, ManySessions) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    std::vector<sp<IBinderRpcSession>> sessions;
+
+    for (size_t i = 0; i < 15; i++) {
+        expectSessions(i, proc.rootIface);
+        sp<IBinderRpcSession> session;
+        EXPECT_OK(proc.rootIface->openSession(std::to_string(i), &session));
+        sessions.push_back(session);
+    }
+    expectSessions(sessions.size(), proc.rootIface);
+    for (size_t i = 0; i < sessions.size(); i++) {
+        std::string out;
+        EXPECT_OK(sessions.at(i)->getName(&out));
+        EXPECT_EQ(std::to_string(i), out);
+    }
+    expectSessions(sessions.size(), proc.rootIface);
+
+    while (!sessions.empty()) {
+        sessions.pop_back();
+        expectSessions(sessions.size(), proc.rootIface);
+    }
+    expectSessions(0, proc.rootIface);
+}
+
+size_t epochMillis() {
+    using std::chrono::duration_cast;
+    using std::chrono::milliseconds;
+    using std::chrono::seconds;
+    using std::chrono::system_clock;
+    return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+}
+
+TEST(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+    constexpr size_t kNumThreads = 10;
+
+    auto proc = createRpcTestSocketServerProcess(kNumThreads);
+
+    EXPECT_OK(proc.rootIface->lock());
+
+    // block all but one thread taking locks
+    std::vector<std::thread> ts;
+    for (size_t i = 0; i < kNumThreads - 1; i++) {
+        ts.push_back(std::thread([&] { proc.rootIface->lockUnlock(); }));
+    }
+
+    usleep(100000); // give chance for calls on other threads
+
+    // other calls still work
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    constexpr size_t blockTimeMs = 500;
+    size_t epochMsBefore = epochMillis();
+    // after this, we should never see a response within this time
+    EXPECT_OK(proc.rootIface->unlockInMsAsync(blockTimeMs));
+
+    // this call should be blocked for blockTimeMs
+    EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+    size_t epochMsAfter = epochMillis();
+    EXPECT_GE(epochMsAfter, epochMsBefore + blockTimeMs) << epochMsBefore;
+
+    for (auto& t : ts) t.join();
+}
+
+TEST(BinderRpc, ThreadPoolOverSaturated) {
+    constexpr size_t kNumThreads = 10;
+    constexpr size_t kNumCalls = kNumThreads + 3;
+    constexpr size_t kSleepMs = 500;
+
+    auto proc = createRpcTestSocketServerProcess(kNumThreads);
+
+    size_t epochMsBefore = epochMillis();
+
+    std::vector<std::thread> ts;
+    for (size_t i = 0; i < kNumCalls; i++) {
+        ts.push_back(std::thread([&] { proc.rootIface->sleepMs(kSleepMs); }));
+    }
+
+    for (auto& t : ts) t.join();
+
+    size_t epochMsAfter = epochMillis();
+
+    EXPECT_GE(epochMsAfter, epochMsBefore + 2 * kSleepMs);
+
+    // Potential flake, but make sure calls are handled in parallel.
+    EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
+}
+
+TEST(BinderRpc, ThreadingStressTest) {
+    constexpr size_t kNumClientThreads = 10;
+    constexpr size_t kNumServerThreads = 10;
+    constexpr size_t kNumCalls = 100;
+
+    auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < kNumClientThreads; i++) {
+        threads.push_back(std::thread([&] {
+            for (size_t j = 0; j < kNumCalls; j++) {
+                sp<IBinder> out;
+                proc.rootIface->repeatBinder(proc.rootBinder, &out);
+                EXPECT_EQ(proc.rootBinder, out);
+            }
+        }));
+    }
+
+    for (auto& t : threads) t.join();
+}
+
+TEST(BinderRpc, OnewayCallDoesNotWait) {
+    constexpr size_t kReallyLongTimeMs = 100;
+    constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
+
+    // more than one thread, just so this doesn't deadlock
+    auto proc = createRpcTestSocketServerProcess(2);
+
+    size_t epochMsBefore = epochMillis();
+
+    EXPECT_OK(proc.rootIface->sleepMsAsync(kSleepMs));
+
+    size_t epochMsAfter = epochMillis();
+    EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
+}
+
+TEST(BinderRpc, OnewayCallQueueing) {
+    constexpr size_t kNumSleeps = 10;
+    constexpr size_t kNumExtraServerThreads = 4;
+    constexpr size_t kSleepMs = 50;
+
+    // make sure calls to the same object happen on the same thread
+    auto proc = createRpcTestSocketServerProcess(1 + kNumExtraServerThreads);
+
+    EXPECT_OK(proc.rootIface->lock());
+
+    for (size_t i = 0; i < kNumSleeps; i++) {
+        // these should be processed serially
+        proc.rootIface->sleepMsAsync(kSleepMs);
+    }
+    // should also be processesed serially
+    EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
+
+    size_t epochMsBefore = epochMillis();
+    EXPECT_OK(proc.rootIface->lockUnlock());
+    size_t epochMsAfter = epochMillis();
+
+    EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+}
+
+TEST(BinderRpc, Die) {
+    // TODO(b/183141167): handle this in library
+    signal(SIGPIPE, SIG_IGN);
+
+    for (bool doDeathCleanup : {true, false}) {
+        auto proc = createRpcTestSocketServerProcess(1);
+
+        // make sure there is some state during crash
+        // 1. we hold their binder
+        sp<IBinderRpcSession> session;
+        EXPECT_OK(proc.rootIface->openSession("happy", &session));
+        // 2. they hold our binder
+        sp<IBinder> binder = new BBinder();
+        EXPECT_OK(proc.rootIface->holdBinder(binder));
+
+        EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
+                << "Do death cleanup: " << doDeathCleanup;
+
+        proc.proc.expectInvalid = true;
+    }
+}
+
+ssize_t countFds() {
+    DIR* dir = opendir("/proc/self/fd/");
+    if (dir == nullptr) return -1;
+    ssize_t ret = 0;
+    dirent* ent;
+    while ((ent = readdir(dir)) != nullptr) ret++;
+    closedir(dir);
+    return ret;
+}
+
+TEST(BinderRpc, Fds) {
+    ssize_t beforeFds = countFds();
+    ASSERT_GE(beforeFds, 0);
+    {
+        auto proc = createRpcTestSocketServerProcess(10);
+        ASSERT_EQ(OK, proc.rootBinder->pingBinder());
+    }
+    ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
+}
+
+extern "C" int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
+    return RUN_ALL_TESTS();
+}
+
+} // namespace android
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 1f2779a..4270540 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -131,6 +131,17 @@
     EXPECT_TRUE(Stability::requiresVintfDeclaration(BadStableBinder::vintf()));
 }
 
+TEST(BinderStability, ForceDowngradeStability) {
+    sp<IBinder> someBinder = BadStableBinder::vintf();
+
+    EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder));
+
+    // silly to do this after already using the binder, but it's for the test
+    Stability::forceDowngradeCompilationUnit(someBinder);
+
+    EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder));
+}
+
 TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
     sp<IBinder> vintfServer = BadStableBinder::vintf();
 
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 7d711c1..c5ee15d 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -479,18 +479,31 @@
     }
     ATRACE_CALL();
 
-    std::lock_guard<std::mutex> lock(mRenderingMutex);
-    auto iter = mTextureCache.find(buffer->getId());
-    if (iter != mTextureCache.end()) {
-        ALOGV("Texture already exists in cache.");
+    // We need to switch the currently bound context if the buffer is protected but the current
+    // context is not. The current state must then be restored after the buffer is cached.
+    const bool protectedContextState = mInProtectedContext;
+    if (!useProtectedContext(protectedContextState ||
+                             (buffer->getUsage() & GRALLOC_USAGE_PROTECTED))) {
+        ALOGE("Attempting to cache a buffer into a different context than what is currently bound");
         return;
+    }
+
+    auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext;
+    auto& cache = mInProtectedContext ? mProtectedTextureCache : mTextureCache;
+
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    auto iter = cache.find(buffer->getId());
+    if (iter != cache.end()) {
+        ALOGV("Texture already exists in cache.");
     } else {
         std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
                 std::make_shared<AutoBackendTexture::LocalRef>();
         imageTextureRef->setTexture(
-                new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), false));
-        mTextureCache.insert({buffer->getId(), imageTextureRef});
+                new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false));
+        cache.insert({buffer->getId(), imageTextureRef});
     }
+    // restore the original state of the protected context if necessary
+    useProtectedContext(protectedContextState);
 }
 
 void SkiaGLRenderEngine::unbindExternalTextureBuffer(uint64_t bufferId) {
@@ -842,15 +855,15 @@
             validateInputBufferUsage(layer->source.buffer.buffer);
             const auto& item = layer->source.buffer;
             std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
-            auto iter = mTextureCache.find(item.buffer->getId());
-            if (iter != mTextureCache.end()) {
+            auto iter = cache.find(item.buffer->getId());
+            if (iter != cache.end()) {
                 imageTextureRef = iter->second;
             } else {
                 imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
                 imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(),
                                                                    item.buffer->toAHardwareBuffer(),
                                                                    false));
-                mTextureCache.insert({item.buffer->getId(), imageTextureRef});
+                cache.insert({item.buffer->getId(), imageTextureRef});
             }
 
             sk_sp<SkImage> image =
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b3f9792..4ace4c2 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -355,6 +355,13 @@
         mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                                clientCompositionTimestamp,
                                                FrameTracer::FrameEvent::FALLBACK_COMPOSITION);
+        // Update the SurfaceFrames in the drawing state
+        if (mDrawingState.bufferSurfaceFrameTX) {
+            mDrawingState.bufferSurfaceFrameTX->setGpuComposition();
+        }
+        for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
+            surfaceFrame->setGpuComposition();
+        }
     }
 
     std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4cd9400..a974dc4 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -692,7 +692,6 @@
         // are processing the next state.
         addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
                                           mDrawingState.acquireFence->getSignalTime(), latchTime);
-        bufferSurfaceFrame.reset();
     }
 
     mCurrentStateModified = false;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index b1dff8d..2784861 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -348,6 +348,11 @@
     mRenderRate = renderRate;
 }
 
+void SurfaceFrame::setGpuComposition() {
+    std::scoped_lock lock(mMutex);
+    mGpuComposition = true;
+}
+
 std::optional<int32_t> SurfaceFrame::getJankType() const {
     std::scoped_lock lock(mMutex);
     if (mPresentState == PresentState::Dropped) {
@@ -828,10 +833,14 @@
 }
 
 void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
-                                 const std::shared_ptr<FenceTime>& presentFence) {
+                                 const std::shared_ptr<FenceTime>& presentFence,
+                                 bool gpuComposition) {
     ATRACE_CALL();
     std::scoped_lock lock(mMutex);
     mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
+    if (gpuComposition) {
+        mCurrentDisplayFrame->setGpuComposition();
+    }
     mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
     flushPendingPresentFences();
     finalizeCurrentDisplayFrame();
@@ -869,6 +878,10 @@
     mSurfaceFlingerActuals.endTime = actualEndTime;
 }
 
+void FrameTimeline::DisplayFrame::setGpuComposition() {
+    mGpuComposition = true;
+}
+
 void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) {
     if (mPredictionState == PredictionState::Expired ||
         mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 3cf35f0..3f04592 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -180,6 +180,7 @@
     void setDropTime(nsecs_t dropTime);
     void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
     void setRenderRate(Fps renderRate);
+    void setGpuComposition();
 
     // When a bufferless SurfaceFrame is promoted to a buffer SurfaceFrame, we also have to update
     // isBuffer.
@@ -292,11 +293,11 @@
     // the token and sets the actualSfWakeTime for the current DisplayFrame.
     virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
 
-    // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence
-    // until it's signaled, and updates the present timestamps of all presented SurfaceFrames in
-    // that vsync.
-    virtual void setSfPresent(nsecs_t sfPresentTime,
-                              const std::shared_ptr<FenceTime>& presentFence) = 0;
+    // Sets the sfPresentTime, gpuComposition and finalizes the current DisplayFrame. Tracks the
+    // given present fence until it's signaled, and updates the present timestamps of all presented
+    // SurfaceFrames in that vsync.
+    virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
+                              bool gpuComposition) = 0;
 
     // Args:
     // -jank : Dumps only the Display Frames that are either janky themselves
@@ -375,6 +376,7 @@
         void setPredictions(PredictionState predictionState, TimelineItem predictions);
         void setActualStartTime(nsecs_t actualStartTime);
         void setActualEndTime(nsecs_t actualEndTime);
+        void setGpuComposition();
 
         // BaseTime is the smallest timestamp in a DisplayFrame.
         // Used for dumping all timestamps relative to the oldest, making it easy to read.
@@ -444,8 +446,8 @@
             int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) override;
     void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
     void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
-    void setSfPresent(nsecs_t sfPresentTime,
-                      const std::shared_ptr<FenceTime>& presentFence) override;
+    void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
+                      bool gpuComposition = false) override;
     void parseArgs(const Vector<String16>& args, std::string& result) override;
     void setMaxDisplayFrames(uint32_t size) override;
     float computeFps(const std::unordered_set<int32_t>& layerIds) override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31097aa..a0dbf6f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2111,7 +2111,8 @@
     // information from previous' frame classification is already available when sending jank info
     // to clients, so they get jank classification as early as possible.
     mFrameTimeline->setSfPresent(systemTime(),
-                                 std::make_shared<FenceTime>(mPreviousPresentFences[0]));
+                                 std::make_shared<FenceTime>(mPreviousPresentFences[0]),
+                                 glCompositionDoneFenceTime != FenceTime::NO_FENCE);
 
     nsecs_t dequeueReadyTime = systemTime();
     for (const auto& layer : mLayersWithQueuedFrames) {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index b9d1794..5707978 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -32,7 +32,7 @@
     MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
     MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
-    MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
+    MOCK_METHOD3(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&, bool));
     MOCK_METHOD1(computeFps, float(const std::unordered_set<int32_t>&));
 };
 
diff --git a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
index 99f592f..a8ddb99 100644
--- a/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorHalWrapperAidlTest.cpp
@@ -31,12 +31,14 @@
 
 using android::binder::Status;
 
+using android::hardware::vibrator::Braking;
 using android::hardware::vibrator::CompositeEffect;
 using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
 using android::hardware::vibrator::EffectStrength;
 using android::hardware::vibrator::IVibrator;
 using android::hardware::vibrator::IVibratorCallback;
+using android::hardware::vibrator::PrimitivePwle;
 
 using namespace android;
 using namespace std::chrono_literals;
@@ -79,6 +81,15 @@
     MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
     MOCK_METHOD(Status, getQFactor, (float * ret), (override));
     MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
+    MOCK_METHOD(Status, getFrequencyResolution, (float *freqResolutionHz), (override));
+    MOCK_METHOD(Status, getFrequencyMinimum, (float *freqMinimumHz), (override));
+    MOCK_METHOD(Status, getBandwidthAmplitudeMap, (std::vector<float> * ret), (override));
+    MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t *durationMs), (override));
+    MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t *maxSize), (override));
+    MOCK_METHOD(Status, getSupportedBraking, (std::vector<Braking> * ret), (override));
+    MOCK_METHOD(Status, composePwle,
+                (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb),
+                (override));
     MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
     MOCK_METHOD(std::string, getInterfaceHash, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
index bcfd15d..b29376b 100644
--- a/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperAidlTest.cpp
@@ -27,6 +27,7 @@
 
 using android::binder::Status;
 
+using android::hardware::vibrator::Braking;
 using android::hardware::vibrator::CompositeEffect;
 using android::hardware::vibrator::CompositePrimitive;
 using android::hardware::vibrator::Effect;
@@ -34,6 +35,7 @@
 using android::hardware::vibrator::IVibrator;
 using android::hardware::vibrator::IVibratorCallback;
 using android::hardware::vibrator::IVibratorManager;
+using android::hardware::vibrator::PrimitivePwle;
 
 using namespace android;
 using namespace testing;
@@ -73,6 +75,15 @@
     MOCK_METHOD(Status, alwaysOnDisable, (int32_t id), (override));
     MOCK_METHOD(Status, getQFactor, (float * ret), (override));
     MOCK_METHOD(Status, getResonantFrequency, (float * ret), (override));
+    MOCK_METHOD(Status, getFrequencyResolution, (float *freqResolutionHz), (override));
+    MOCK_METHOD(Status, getFrequencyMinimum, (float *freqMinimumHz), (override));
+    MOCK_METHOD(Status, getBandwidthAmplitudeMap, (std::vector<float> * ret), (override));
+    MOCK_METHOD(Status, getPwlePrimitiveDurationMax, (int32_t *durationMs), (override));
+    MOCK_METHOD(Status, getPwleCompositionSizeMax, (int32_t *maxSize), (override));
+    MOCK_METHOD(Status, getSupportedBraking, (std::vector<Braking> * ret), (override));
+    MOCK_METHOD(Status, composePwle,
+                (const std::vector<PrimitivePwle>& e, const sp<IVibratorCallback>& cb),
+                (override));
     MOCK_METHOD(int32_t, getInterfaceVersion, (), (override));
     MOCK_METHOD(std::string, getInterfaceHash, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));