Skip to content

Commit 4f1c485

Browse files
Treehugger Robotandroid-build-merge-worker-robot
authored andcommitted
Merge "Revert "lshal: use std::async"" into main am: cb59ad9
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2942572 Change-Id: Iff5825fb2b77173745a1cc069876bae9ea15074b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
2 parents 8bc3752 + cb59ad9 commit 4f1c485

3 files changed

Lines changed: 73 additions & 143 deletions

File tree

cmds/lshal/Timeout.h

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,44 +16,83 @@
1616

1717
#pragma once
1818

19+
#include <condition_variable>
1920
#include <chrono>
20-
#include <future>
21+
#include <functional>
22+
#include <mutex>
23+
#include <thread>
2124

2225
#include <hidl/Status.h>
23-
#include <utils/Errors.h>
2426

2527
namespace android {
2628
namespace lshal {
2729

28-
// Call function on interfaceObject and wait for result until the given timeout has reached.
29-
// Callback functions pass to timeoutIPC() may be executed after the this function
30-
// has returned, especially if deadline has been reached. Hence, care must be taken when passing
31-
// data between the background thread and the main thread. See b/311143089.
30+
class BackgroundTaskState {
31+
public:
32+
explicit BackgroundTaskState(std::function<void(void)> &&func)
33+
: mFunc(std::forward<decltype(func)>(func)) {}
34+
void notify() {
35+
std::unique_lock<std::mutex> lock(mMutex);
36+
mFinished = true;
37+
lock.unlock();
38+
mCondVar.notify_all();
39+
}
40+
template<class C, class D>
41+
bool wait(std::chrono::time_point<C, D> end) {
42+
std::unique_lock<std::mutex> lock(mMutex);
43+
mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
44+
return mFinished;
45+
}
46+
void operator()() {
47+
mFunc();
48+
}
49+
private:
50+
std::mutex mMutex;
51+
std::condition_variable mCondVar;
52+
bool mFinished = false;
53+
std::function<void(void)> mFunc;
54+
};
55+
56+
void *callAndNotify(void *data) {
57+
BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
58+
state();
59+
state.notify();
60+
return nullptr;
61+
}
62+
63+
template<class R, class P>
64+
bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
65+
auto now = std::chrono::system_clock::now();
66+
BackgroundTaskState state{std::forward<decltype(func)>(func)};
67+
pthread_t thread;
68+
if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
69+
std::cerr << "FATAL: could not create background thread." << std::endl;
70+
return false;
71+
}
72+
bool success = state.wait(now + delay);
73+
if (!success) {
74+
pthread_kill(thread, SIGINT);
75+
}
76+
pthread_join(thread, nullptr);
77+
return success;
78+
}
79+
3280
template<class R, class P, class Function, class I, class... Args>
3381
typename std::invoke_result<Function, I *, Args...>::type
3482
timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func,
3583
Args &&... args) {
3684
using ::android::hardware::Status;
37-
38-
// Execute on a background thread but do not defer execution.
39-
auto future =
40-
std::async(std::launch::async, func, interfaceObject, std::forward<Args>(args)...);
41-
auto status = future.wait_for(wait);
42-
if (status == std::future_status::ready) {
43-
return future.get();
44-
}
45-
46-
// This future belongs to a background thread that we no longer care about.
47-
// Putting this in the global list avoids std::future::~future() that may wait for the
48-
// result to come back.
49-
// This leaks memory, but lshal is a debugging tool, so this is fine.
50-
static std::vector<decltype(future)> gDeadPool{};
51-
gDeadPool.emplace_back(std::move(future));
52-
53-
if (status == std::future_status::timeout) {
85+
typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
86+
auto boundFunc = std::bind(std::forward<Function>(func),
87+
interfaceObject.get(), std::forward<Args>(args)...);
88+
bool success = timeout(wait, [&ret, &boundFunc] {
89+
ret = std::move(boundFunc());
90+
});
91+
if (!success) {
5492
return Status::fromStatusT(TIMED_OUT);
5593
}
56-
return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE, "Illegal future_status");
94+
return ret;
5795
}
58-
} // namespace lshal
59-
} // namespace android
96+
97+
} // namespace lshal
98+
} // namespace android

cmds/lshal/main.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,5 @@
1818

1919
int main(int argc, char **argv) {
2020
using namespace ::android::lshal;
21-
// Use _exit() to force terminate background threads in Timeout.h
22-
_exit(Lshal{}.main(Arg{argc, argv}));
21+
return Lshal{}.main(Arg{argc, argv});
2322
}

cmds/lshal/test.cpp

Lines changed: 7 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17-
#include <chrono>
18-
#include <future>
19-
#include <mutex>
20-
#include "android/hidl/base/1.0/IBase.h"
2117
#define LOG_TAG "Lshal"
2218
#include <android-base/logging.h>
2319

@@ -40,8 +36,6 @@
4036

4137
using namespace testing;
4238

43-
using std::chrono_literals::operator""ms;
44-
4539
using ::android::hidl::base::V1_0::DebugInfo;
4640
using ::android::hidl::base::V1_0::IBase;
4741
using ::android::hidl::manager::V1_0::IServiceManager;
@@ -940,9 +934,12 @@ TEST_F(ListTest, DumpDebug) {
940934
return hardware::Void();
941935
}));
942936
EXPECT_CALL(*serviceManager, get(_, _))
943-
.WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
944-
return sp<IBase>(service);
945-
}));
937+
.WillRepeatedly(
938+
Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
939+
int id = getIdFromInstanceName(instance);
940+
if (id > inheritanceLevel) return nullptr;
941+
return sp<IBase>(service);
942+
}));
946943

947944
const std::string expected = "[fake description 0]\n"
948945
"Interface\n"
@@ -960,110 +957,6 @@ TEST_F(ListTest, DumpDebug) {
960957
EXPECT_EQ("", err.str());
961958
}
962959

963-
// In SlowService, everything goes slooooooow. Each IPC call will wait for
964-
// the specified time before calling the callback function or returning.
965-
class SlowService : public IBase {
966-
public:
967-
explicit SlowService(std::chrono::milliseconds wait) : mWait(wait) {}
968-
android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
969-
std::this_thread::sleep_for(mWait);
970-
cb(getInterfaceName(1));
971-
storeHistory("interfaceDescriptor");
972-
return hardware::Void();
973-
}
974-
android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
975-
std::this_thread::sleep_for(mWait);
976-
std::vector<hidl_string> ret;
977-
ret.push_back(getInterfaceName(1));
978-
ret.push_back(IBase::descriptor);
979-
cb(ret);
980-
storeHistory("interfaceChain");
981-
return hardware::Void();
982-
}
983-
android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
984-
std::this_thread::sleep_for(mWait);
985-
std::vector<hidl_hash> ret;
986-
ret.push_back(getHashFromId(0));
987-
ret.push_back(getHashFromId(0xff));
988-
cb(ret);
989-
storeHistory("getHashChain");
990-
return hardware::Void();
991-
}
992-
android::hardware::Return<void> debug(const hidl_handle&,
993-
const hidl_vec<hidl_string>&) override {
994-
std::this_thread::sleep_for(mWait);
995-
storeHistory("debug");
996-
return Void();
997-
}
998-
999-
template <class R, class P, class Pred>
1000-
bool waitForHistory(std::chrono::duration<R, P> wait, Pred predicate) {
1001-
std::unique_lock<std::mutex> lock(mLock);
1002-
return mCv.wait_for(lock, wait, [&]() { return predicate(mCallHistory); });
1003-
}
1004-
1005-
private:
1006-
void storeHistory(std::string hist) {
1007-
{
1008-
std::lock_guard<std::mutex> lock(mLock);
1009-
mCallHistory.emplace_back(std::move(hist));
1010-
}
1011-
mCv.notify_all();
1012-
}
1013-
1014-
const std::chrono::milliseconds mWait;
1015-
std::mutex mLock;
1016-
std::condition_variable mCv;
1017-
// List of functions that have finished being called on this interface.
1018-
std::vector<std::string> mCallHistory;
1019-
};
1020-
1021-
class TimeoutTest : public ListTest {
1022-
public:
1023-
void setMockServiceManager(sp<IBase> service) {
1024-
EXPECT_CALL(*serviceManager, list(_))
1025-
.WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
1026-
std::vector<hidl_string> ret;
1027-
ret.push_back(getInterfaceName(1) + "/default");
1028-
cb(ret);
1029-
return hardware::Void();
1030-
}));
1031-
EXPECT_CALL(*serviceManager, get(_, _))
1032-
.WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> {
1033-
return service;
1034-
}));
1035-
}
1036-
};
1037-
1038-
TEST_F(TimeoutTest, BackgroundThreadIsKept) {
1039-
auto lshalIpcTimeout = 100ms;
1040-
auto serviceIpcTimeout = 200ms;
1041-
lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
1042-
sp<SlowService> service = new SlowService(serviceIpcTimeout);
1043-
setMockServiceManager(service);
1044-
1045-
optind = 1; // mimic Lshal::parseArg()
1046-
EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
1047-
EXPECT_THAT(err.str(), HasSubstr("Skipping \"a.h.foo1@1.0::IFoo/default\""));
1048-
EXPECT_TRUE(service->waitForHistory(serviceIpcTimeout * 5, [](const auto& hist) {
1049-
return hist.size() == 1 && hist[0] == "interfaceChain";
1050-
})) << "The background thread should continue after the main thread moves on, but it is killed";
1051-
}
1052-
1053-
TEST_F(TimeoutTest, BackgroundThreadDoesNotBlockMainThread) {
1054-
auto lshalIpcTimeout = 100ms;
1055-
auto serviceIpcTimeout = 2000ms;
1056-
auto start = std::chrono::system_clock::now();
1057-
lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout);
1058-
sp<SlowService> service = new SlowService(serviceIpcTimeout);
1059-
setMockServiceManager(service);
1060-
1061-
optind = 1; // mimic Lshal::parseArg()
1062-
EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"})));
1063-
EXPECT_LE(std::chrono::system_clock::now(), start + 5 * lshalIpcTimeout)
1064-
<< "The main thread should not be blocked by the background task";
1065-
}
1066-
1067960
class ListVintfTest : public ListTest {
1068961
public:
1069962
virtual void SetUp() override {
@@ -1186,6 +1079,5 @@ TEST_F(HelpTest, UnknownOptionHelp2) {
11861079

11871080
int main(int argc, char **argv) {
11881081
::testing::InitGoogleMock(&argc, argv);
1189-
// Use _exit() to force terminate background threads in Timeout.h
1190-
_exit(RUN_ALL_TESTS());
1082+
return RUN_ALL_TESTS();
11911083
}

0 commit comments

Comments
 (0)