Merge "gpu mem bpf program - switch to LICENSE macro"
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 18c267d..619579e 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -191,6 +191,10 @@
         "libbase",
         "liblog",
         "libutils",
+        "libbinder",
+    ],
+    static_libs: [
+      "ota_dexopt_aidl_interface-cpp",
     ],
     required: [
       "apexd"
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 15f0c5b..cd5c36f 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -492,6 +492,14 @@
                  std::to_string(min_new_methods_percent_change));
         }
 
+        // On-device signing related. odsign sets the system property odsign.verification.success if
+        // AOT artifacts have the expected signatures.
+        const bool trust_art_apex_data_files =
+                ::android::base::GetBoolProperty("odsign.verification.success", false);
+        if (!trust_art_apex_data_files) {
+            AddRuntimeArg("-Xdeny-art-apex-data-files");
+        }
+
         // Do not add after dex2oat_flags, they should override others for debugging.
         PrepareArgs(profman_bin);
     }
@@ -1231,6 +1239,14 @@
             }
         }
 
+        // On-device signing related. odsign sets the system property odsign.verification.success if
+        // AOT artifacts have the expected signatures.
+        const bool trust_art_apex_data_files =
+                ::android::base::GetBoolProperty("odsign.verification.success", false);
+        if (!trust_art_apex_data_files) {
+            AddRuntimeArg("-Xdeny-art-apex-data-files");
+        }
+
         PrepareArgs(dexoptanalyzer_bin);
     }
 
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index c62734a..7fcce2c 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -21,15 +21,21 @@
 #include <sys/wait.h>
 
 #include <array>
+#include <chrono>
 #include <fstream>
 #include <sstream>
+#include <thread>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/parseint.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <android/content/pm/IOtaDexopt.h>
+#include <binder/IServiceManager.h>
 #include <libdm/dm.h>
 #include <selinux/android.h>
 
@@ -45,6 +51,8 @@
 namespace android {
 namespace installd {
 
+using namespace std::literals::chrono_literals;
+
 static void CloseDescriptor(int fd) {
     if (fd >= 0) {
         int result = close(fd);
@@ -53,15 +61,6 @@
     }
 }
 
-static void CloseDescriptor(const char* descriptor_string) {
-    int fd = -1;
-    std::istringstream stream(descriptor_string);
-    stream >> fd;
-    if (!stream.fail()) {
-        CloseDescriptor(fd);
-    }
-}
-
 static void ActivateApexPackages() {
     std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--otachroot-bootstrap"};
     std::string apexd_error_msg;
@@ -113,6 +112,38 @@
     UNUSED(mount_result);
 }
 
+static android::sp<android::content::pm::IOtaDexopt> GetDexoptService() {
+    auto binder = android::defaultServiceManager()->getService(android::String16("otadexopt"));
+    if (binder == nullptr) {
+        return nullptr;
+    }
+    return android::interface_cast<android::content::pm::IOtaDexopt>(binder);
+}
+
+static bool RunDexoptCommand(int argc, char **arg, const std::string& dexopt_cmd) {
+    // Incoming:  cmd + status-fd + target-slot + cmd...      | Incoming | = argc
+    // Outgoing:  cmd             + target-slot + cmd...      | Outgoing | = argc - 1
+    std::vector<std::string> cmd;
+    cmd.reserve(argc);
+    cmd.push_back("/system/bin/otapreopt");
+
+    // The first parameter is the status file descriptor, skip.
+    for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
+        cmd.push_back(arg[i]);
+    }
+    for (const std::string& part : android::base::Split(dexopt_cmd, " ")) {
+        cmd.push_back(part);
+    }
+
+    // Fork and execute otapreopt in its own process.
+    std::string error_msg;
+    bool exec_result = Exec(cmd, &error_msg);
+    if (!exec_result) {
+        LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+    }
+    return exec_result;
+}
+
 // Entry for otapreopt_chroot. Expected parameters are:
 //   [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
 // The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -130,8 +161,18 @@
     CloseDescriptor(STDIN_FILENO);
     CloseDescriptor(STDOUT_FILENO);
     CloseDescriptor(STDERR_FILENO);
-    // 2) The status channel.
-    CloseDescriptor(arg[1]);
+
+    int fd;
+    if (!android::base::ParseInt(arg[1], &fd)) {
+        LOG(ERROR) << "Failed to parse " << arg[1];
+        exit(225);
+    }
+    // Add O_CLOEXEC to status channel, since we don't want to pass it across fork/exec, but we need
+    // to keep it open in otapreopt_chroot to report progress
+    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+        PLOG(ERROR) << "Failed to set O_CLOEXEC on " << fd;
+        exit(226);
+    }
 
     // We need to run the otapreopt tool from the postinstall partition. As such, set up a
     // mount namespace and change root.
@@ -313,28 +354,50 @@
         exit(218);
     }
 
+    android::sp<android::content::pm::IOtaDexopt> dexopt = GetDexoptService();
+    if (dexopt == nullptr) {
+        LOG(ERROR) << "Failed to find otadexopt service";
+        exit(222);
+    }
+
+    android::base::borrowed_fd status_fd(fd);
     // Now go on and run otapreopt.
+    constexpr const int kMaximumPackages = 1000;
+    for (int iter = 0; iter < kMaximumPackages; iter++) {
+        android::String16 cmd;
+        android::binder::Status status = dexopt->nextDexoptCommand(&cmd);
+        if (!status.isOk()) {
+            LOG(ERROR) << "Failed to retrieve next dexopt command";
+            // Should we fail instead?
+            exit(224);
+        }
+        if (!RunDexoptCommand(argc, arg, android::String8(cmd).string())) {
+            exit(213);
+        }
 
-    // Incoming:  cmd + status-fd + target-slot + cmd...      | Incoming | = argc
-    // Outgoing:  cmd             + target-slot + cmd...      | Outgoing | = argc - 1
-    std::vector<std::string> cmd;
-    cmd.reserve(argc);
-    cmd.push_back("/system/bin/otapreopt");
+        float progress;
+        status = dexopt->getProgress(&progress);
+        if (!status.isOk()) {
+            LOG(ERROR) << "Failed to retrieve dexopt progress";
+            continue;
+        }
+        LOG(VERBOSE) << "Progress: " << progress;
+        std::string progress_str = StringPrintf("global_progress %.2f\n", progress);
+        if (!android::base::WriteStringToFd(progress_str, status_fd)) {
+            PLOG(ERROR) << "Failed to write '" << progress_str << "' to " << status_fd.get();
+        }
 
-    // The first parameter is the status file descriptor, skip.
-    for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
-        cmd.push_back(arg[i]);
-    }
-
-    // Fork and execute otapreopt in its own process.
-    std::string error_msg;
-    bool exec_result = Exec(cmd, &error_msg);
-    if (!exec_result) {
-        LOG(ERROR) << "Running otapreopt failed: " << error_msg;
-    }
-
-    if (!exec_result) {
-        exit(213);
+        bool done;
+        status = dexopt->isDone(&done);
+        if (!status.isOk()) {
+            LOG(WARNING) << "Failed to check if dexopt is done";
+            continue;
+        }
+        if (done) {
+            LOG(INFO) << "dexopt is done";
+            break;
+        }
+        std::this_thread::sleep_for(1s);
     }
 
     return 0;
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index f950276..8bcbc9f 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -58,23 +58,7 @@
 PROGRESS=$(cmd otadexopt progress)
 print -u${STATUS_FD} "global_progress $PROGRESS"
 
-i=0
-while ((i<MAXIMUM_PACKAGES)) ; do
-  DEXOPT_PARAMS=$(cmd otadexopt next)
-
-  /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&-
-
-  PROGRESS=$(cmd otadexopt progress)
-  print -u${STATUS_FD} "global_progress $PROGRESS"
-
-  DONE=$(cmd otadexopt done)
-  if [ "$DONE" = "OTA incomplete." ] ; then
-    sleep 1
-    i=$((i+1))
-    continue
-  fi
-  break
-done
+/system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&-
 
 DONE=$(cmd otadexopt done)
 if [ "$DONE" = "OTA incomplete." ] ; then
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index e847626..b661684 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -283,6 +283,13 @@
         }
     }
 
+    // On-device signing related. odsign sets the system property odsign.verification.success if
+    // AOT artifacts have the expected signatures.
+    const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false);
+    if (!trust_art_apex_data_files) {
+        AddRuntimeArg("-Xdeny-art-apex-data-files");
+    }
+
     if (target_sdk_version != 0) {
         AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
     }
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 748fa72..269b867 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -16,6 +16,9 @@
       "name": "binderDriverInterfaceTest"
     },
     {
+      "name": "binderHostDeviceTest"
+    },
+    {
       "name": "binderTextOutputTest"
     },
     {
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 9e4475c..42c85f9 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -42,6 +42,7 @@
         }
         mStability = other.mStability;
     }
+    ParcelableHolder(ParcelableHolder&& other) = default;
 
     status_t writeToParcel(Parcel* parcel) const override;
     status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index b89714a..2abb6f7 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -233,13 +233,15 @@
 
 void ABpBinder::onLastStrongRef(const void* id) {
     // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
-    // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no
-    // longer be able to exist at the time of this method call, there is no longer a need to
-    // recover it.
+    // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
+    // (BpRefBase), the remote object may still exist (for instance, if we
+    // receive it from another process, before the ABpBinder is attached).
 
     ABpBinderTag::Value* value =
-            static_cast<ABpBinderTag::Value*>(remote()->detachObject(ABpBinderTag::kId));
-    if (value) ABpBinderTag::clean(ABpBinderTag::kId, value, nullptr /*cookie*/);
+            static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
+    CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
+
+    remote()->withLock([&]() { value->binder = nullptr; });
 
     BpRefBase::onLastStrongRef(id);
 }
@@ -252,6 +254,9 @@
         return static_cast<ABBinder*>(binder.get());
     }
 
+    // The following code ensures that for a given binder object (remote or local), if it is not an
+    // ABBinder then at most one ABpBinder object exists in a given process representing it.
+
     auto* value = static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
     if (value == nullptr) {
         value = new ABpBinderTag::Value;
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 2277148..aa3b978 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -46,7 +46,7 @@
     AParcelableHolder() = delete;
     explicit AParcelableHolder(parcelable_stability_t stability)
         : mParcel(AParcel_create()), mStability(stability) {}
-
+    AParcelableHolder(AParcelableHolder&& other) = default;
     virtual ~AParcelableHolder() = default;
 
     binder_status_t writeToParcel(AParcel* parcel) const {
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 1c43948..5ad390e 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,6 +39,7 @@
 #include <condition_variable>
 #include <iostream>
 #include <mutex>
+#include <thread>
 #include "android/binder_ibinder.h"
 
 using namespace android;
@@ -250,6 +251,27 @@
     EXPECT_EQ(2, out);
 }
 
+TEST(NdkBinder, GetTestServiceStressTest) {
+    // libbinder has some complicated logic to make sure only one instance of
+    // ABpBinder is associated with each binder.
+
+    constexpr size_t kNumThreads = 10;
+    constexpr size_t kNumCalls = 1000;
+    std::vector<std::thread> threads;
+
+    for (size_t i = 0; i < kNumThreads; i++) {
+        threads.push_back(std::thread([&]() {
+            for (size_t j = 0; j < kNumCalls; j++) {
+                auto binder =
+                        ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+                EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+            }
+        }));
+    }
+
+    for (auto& thread : threads) thread.join();
+}
+
 void defaultInstanceCounter(const char* instance, void* context) {
     if (strcmp(instance, "default") == 0) {
         ++*(size_t*)(context);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 565f88e..24afcf6 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -348,3 +348,49 @@
         },
     },
 }
+
+cc_test_host {
+    name: "binderHostDeviceTest",
+    defaults: ["binder_test_defaults"],
+    srcs: ["binderHostDeviceTest.cpp"],
+    test_config: "binderHostDeviceTest.xml",
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    target_required: [
+        "binderHostDeviceTestService",
+    ],
+    test_suites: ["general-tests"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    test_options: {
+        unit_test: false,
+    },
+}
+
+cc_test {
+    name: "binderHostDeviceTestService",
+    // The binary is named differently from the module so that PushFilePreparer pushes the binary
+    // directly, not the test module directory.
+    stem: "binderHostDeviceTest-service",
+    defaults: ["binder_test_defaults"],
+    gtest: false,
+    auto_gen_config: false,
+    srcs: ["binderHostDeviceTestService.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
new file mode 100644
index 0000000..5dd9212
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+// Integration test for servicedispatcher + adb forward. Requires ADB.
+
+#include <stdlib.h>
+
+#include <vector>
+
+#include <android-base/parsebool.h>
+#include <android-base/result-gmock.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "../UtilsHost.h"
+
+using ::android::setDefaultServiceManager;
+using ::android::base::EndsWith;
+using ::android::base::Join;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
+using ::android::base::Split;
+using ::android::base::StartsWith;
+using ::android::base::StringReplace;
+using ::android::base::Trim;
+using ::android::base::testing::Ok;
+using ::std::chrono_literals::operator""ms;
+using ::std::string_literals::operator""s;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::ContainsRegex;
+using ::testing::ExplainMatchResult;
+using ::testing::InitGoogleMock;
+
+namespace android {
+
+namespace {
+
+constexpr const char* kServiceBinary = "/data/local/tmp/binderHostDeviceTest-service";
+constexpr const char* kServiceName = "binderHostDeviceTestService";
+constexpr const char* kDescriptor = "android.binderHostDeviceTestService";
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+    *result_listener << statusToString(arg);
+    return expected == arg;
+}
+
+void initHostRpcServiceManagerOnce() {
+    static std::once_flag gSmOnce;
+    std::call_once(gSmOnce, [] { setDefaultServiceManager(createRpcDelegateServiceManager()); });
+}
+
+// Test for host service manager.
+class HostDeviceTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        auto debuggableResult = execute(Split("adb shell getprop ro.debuggable", " "), nullptr);
+        ASSERT_THAT(debuggableResult, Ok());
+        ASSERT_EQ(0, debuggableResult->exitCode) << *debuggableResult;
+        auto debuggableBool = ParseBool(Trim(debuggableResult->stdout));
+        ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdout);
+        if (debuggableBool == ParseBoolResult::kFalse) {
+            GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdout);
+        }
+
+        auto lsResult = execute(Split("adb shell which servicedispatcher", " "), nullptr);
+        ASSERT_THAT(lsResult, Ok());
+        if (lsResult->exitCode != 0) {
+            GTEST_SKIP() << "b/182914638: until feature is fully enabled, skip test on devices "
+                            "without servicedispatcher";
+        }
+
+        initHostRpcServiceManagerOnce();
+        ASSERT_NE(nullptr, defaultServiceManager()) << "No defaultServiceManager() over RPC";
+
+        auto service = execute({"adb", "shell", kServiceBinary, kServiceName, kDescriptor},
+                               &CommandResult::stdoutEndsWithNewLine);
+        ASSERT_THAT(service, Ok());
+        ASSERT_EQ(std::nullopt, service->exitCode) << *service;
+        mService = std::move(*service);
+    }
+    void TearDown() override { mService.reset(); }
+
+    [[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
+        auto rpcSession = RpcSession::make();
+        if (!rpcSession->setupInetClient("127.0.0.1", hostPort)) {
+            ADD_FAILURE() << "Failed to setupInetClient on " << hostPort;
+            return nullptr;
+        }
+        return rpcSession->getRootObject();
+    }
+
+private:
+    std::optional<CommandResult> mService;
+};
+
+TEST_F(HostDeviceTest, List) {
+    auto sm = defaultServiceManager();
+
+    auto services = sm->listServices();
+    ASSERT_THAT(services, Contains(String16(kServiceName)));
+}
+
+TEST_F(HostDeviceTest, CheckService) {
+    auto sm = defaultServiceManager();
+
+    auto rpcBinder = sm->checkService(String16(kServiceName));
+    ASSERT_NE(nullptr, rpcBinder);
+
+    EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+    EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, GetService) {
+    auto sm = defaultServiceManager();
+
+    auto rpcBinder = sm->getService(String16(kServiceName));
+    ASSERT_NE(nullptr, rpcBinder);
+
+    EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+    EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, WaitForService) {
+    auto sm = defaultServiceManager();
+
+    auto rpcBinder = sm->waitForService(String16(kServiceName));
+    ASSERT_NE(nullptr, rpcBinder);
+
+    EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+    EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, TenClients) {
+    auto sm = defaultServiceManager();
+
+    auto threadFn = [&] {
+        auto rpcBinder = sm->checkService(String16(kServiceName));
+        ASSERT_NE(nullptr, rpcBinder);
+
+        EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+        EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+    };
+
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < 10; ++i) threads.emplace_back(threadFn);
+    for (auto& thread : threads) thread.join();
+}
+
+} // namespace
+
+} // namespace android
diff --git a/libs/binder/tests/binderHostDeviceTest.xml b/libs/binder/tests/binderHostDeviceTest.xml
new file mode 100644
index 0000000..250ed3a
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs binderHostDeviceTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="binderHostDeviceTest-service"
+                value="/data/local/tmp/binderHostDeviceTest-service"/>
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.binary.ExecutableHostTest">
+        <option name="binary" value="binderHostDeviceTest"/>
+    </test>
+</configuration>
diff --git a/libs/binder/tests/binderHostDeviceTestService.cpp b/libs/binder/tests/binderHostDeviceTestService.cpp
new file mode 100644
index 0000000..6ddd2e7
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTestService.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <sysexits.h>
+
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+namespace {
+class Service : public android::BBinder {
+public:
+    Service(std::string_view descriptor) : mDescriptor(descriptor.data(), descriptor.size()) {}
+    const android::String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+private:
+    android::String16 mDescriptor;
+};
+} // namespace
+
+int main(int argc, char** argv) {
+    if (argc != 3) {
+        std::cerr << "usage: " << argv[0] << " <service-name> <interface-descriptor>" << std::endl;
+        return EX_USAGE;
+    }
+    auto name = argv[1];
+    auto descriptor = argv[2];
+
+    auto sm = android::defaultServiceManager();
+    CHECK(sm != nullptr);
+    auto service = android::sp<Service>::make(descriptor);
+    auto status = sm->addService(android::String16(name), service);
+    CHECK_EQ(android::OK, status) << android::statusToString(status);
+    std::cout << "running..." << std::endl;
+    android::ProcessState::self()->startThreadPool();
+    android::IPCThreadState::self()->joinThreadPool();
+    LOG(ERROR) << "joinThreadPool exits";
+    return EX_SOFTWARE;
+}