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

Commit 77d8f5b5 authored by Steven Moreland's avatar Steven Moreland Committed by Gerrit Code Review
Browse files

Merge "libbinder_ndk: test Bp destruction"

parents 40927e84 169bb8f0
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -59,6 +59,9 @@ cc_test {
    name: "libbinder_ndk_unit_test",
    name: "libbinder_ndk_unit_test",
    defaults: ["test_libbinder_ndk_test_defaults"],
    defaults: ["test_libbinder_ndk_test_defaults"],
    srcs: ["libbinder_ndk_unit_test.cpp"],
    srcs: ["libbinder_ndk_unit_test.cpp"],
    static_libs: [
        "IBinderNdkUnitTest-ndk_platform",
    ],
    test_suites: ["general-tests"],
    test_suites: ["general-tests"],
    require_root: true,
    require_root: true,


@@ -93,3 +96,11 @@ aidl_interface {
        "IBinderVendorDoubleLoadTest.aidl",
        "IBinderVendorDoubleLoadTest.aidl",
    ],
    ],
}
}

aidl_interface {
    name: "IBinderNdkUnitTest",
    srcs: [
        "IBinderNdkUnitTest.aidl",
        "IEmpty.aidl",
    ],
}
+27 −0
Original line number Original line Diff line number Diff line
/*
 * 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.
 */

// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases
// because it requires libbinder_ndk implementation details or APIs not
// available to apps. Please prefer adding tests to CtsNdkBinderTestCases
// over here.

import IEmpty;

interface IBinderNdkUnitTest {
    void takeInterface(IEmpty test);
    void forceFlushCommands();
}
+17 −0
Original line number Original line Diff line number Diff line
/*
 * 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 IEmpty { }
+78 −3
Original line number Original line Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


#include <aidl/BnBinderNdkUnitTest.h>
#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
#include <android-base/logging.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_manager.h>
#include <android/binder_manager.h>
@@ -21,6 +23,10 @@
#include <gtest/gtest.h>
#include <gtest/gtest.h>
#include <iface/iface.h>
#include <iface/iface.h>


// warning: this is assuming that libbinder_ndk is using the same copy
// of libbinder that we are.
#include <binder/IPCThreadState.h>

#include <sys/prctl.h>
#include <sys/prctl.h>
#include <chrono>
#include <chrono>
#include <condition_variable>
#include <condition_variable>
@@ -29,7 +35,38 @@
using ::android::sp;
using ::android::sp;


constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";

class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
    ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) {
        (void)empty;
        return ndk::ScopedAStatus::ok();
    }
    ndk::ScopedAStatus forceFlushCommands() {
        // warning: this is assuming that libbinder_ndk is using the same copy
        // of libbinder that we are.
        android::IPCThreadState::self()->flushCommands();
        return ndk::ScopedAStatus::ok();
    }
};

int generatedService() {
    ABinderProcess_setThreadPoolMaxThreadCount(0);

    auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
    binder_status_t status =
            AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService);

    if (status != STATUS_OK) {
        LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService;
    }

    ABinderProcess_joinThreadPool();

    return 1;  // should not return
}


// manually-written parceling class considered bad practice
class MyFoo : public IFoo {
class MyFoo : public IFoo {
    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
    binder_status_t doubleNumber(int32_t in, int32_t* out) override {
        *out = 2 * in;
        *out = 2 * in;
@@ -43,7 +80,7 @@ class MyFoo : public IFoo {
    }
    }
};
};


int service(const char* instance) {
int manualService(const char* instance) {
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    ABinderProcess_setThreadPoolMaxThreadCount(0);


    // Strong reference to MyFoo kept by service manager.
    // Strong reference to MyFoo kept by service manager.
@@ -225,16 +262,54 @@ TEST(NdkBinder, AddServiceMultipleTimes) {
    EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
    EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
}


TEST(NdkBinder, SentAidlBinderCanBeDestroyed) {
    static volatile bool destroyed = false;
    static std::mutex dMutex;
    static std::condition_variable cv;

    class MyEmpty : public aidl::BnEmpty {
        virtual ~MyEmpty() {
            destroyed = true;
            cv.notify_one();
        }
    };

    std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>();

    ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService));
    std::shared_ptr<aidl::IBinderNdkUnitTest> service =
            aidl::IBinderNdkUnitTest::fromBinder(binder);

    EXPECT_FALSE(destroyed);

    service->takeInterface(empty);
    service->forceFlushCommands();
    empty = nullptr;

    // give other binder thread time to process commands
    {
        using namespace std::chrono_literals;
        std::unique_lock<std::mutex> lk(dMutex);
        cv.wait_for(lk, 1s, [] { return destroyed; });
    }

    EXPECT_TRUE(destroyed);
}

int main(int argc, char* argv[]) {
int main(int argc, char* argv[]) {
    ::testing::InitGoogleTest(&argc, argv);
    ::testing::InitGoogleTest(&argc, argv);


    if (fork() == 0) {
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return service(IFoo::kInstanceNameToDieFor);
        return manualService(IFoo::kInstanceNameToDieFor);
    }
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return manualService(IFoo::kSomeInstanceName);
    }
    }
    if (fork() == 0) {
    if (fork() == 0) {
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        return service(IFoo::kSomeInstanceName);
        return generatedService();
    }
    }


    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks
    ABinderProcess_setThreadPoolMaxThreadCount(1);  // to recieve death notifications/callbacks