Loading cmds/dumpstate/dumpstate.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -1563,6 +1563,13 @@ static void DumpstateLimitedOnly() { RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"}); RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"}); printf("========================================================\n"); printf("== ANR Traces\n"); printf("========================================================\n"); AddAnrTraceFiles(); printf("========================================================\n"); printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(), ds.progress_->GetMax(), ds.progress_->GetInitialMax()); Loading cmds/lshal/Timeout.h +65 −26 Original line number Diff line number Diff line Loading @@ -16,44 +16,83 @@ #pragma once #include <condition_variable> #include <chrono> #include <future> #include <functional> #include <mutex> #include <thread> #include <hidl/Status.h> #include <utils/Errors.h> namespace android { namespace lshal { // Call function on interfaceObject and wait for result until the given timeout has reached. // Callback functions pass to timeoutIPC() may be executed after the this function // has returned, especially if deadline has been reached. Hence, care must be taken when passing // data between the background thread and the main thread. See b/311143089. class BackgroundTaskState { public: explicit BackgroundTaskState(std::function<void(void)> &&func) : mFunc(std::forward<decltype(func)>(func)) {} void notify() { std::unique_lock<std::mutex> lock(mMutex); mFinished = true; lock.unlock(); mCondVar.notify_all(); } template<class C, class D> bool wait(std::chrono::time_point<C, D> end) { std::unique_lock<std::mutex> lock(mMutex); mCondVar.wait_until(lock, end, [this](){ return this->mFinished; }); return mFinished; } void operator()() { mFunc(); } private: std::mutex mMutex; std::condition_variable mCondVar; bool mFinished = false; std::function<void(void)> mFunc; }; void *callAndNotify(void *data) { BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data); state(); state.notify(); return nullptr; } template<class R, class P> bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) { auto now = std::chrono::system_clock::now(); BackgroundTaskState state{std::forward<decltype(func)>(func)}; pthread_t thread; if (pthread_create(&thread, nullptr, callAndNotify, &state)) { std::cerr << "FATAL: could not create background thread." << std::endl; return false; } bool success = state.wait(now + delay); if (!success) { pthread_kill(thread, SIGINT); } pthread_join(thread, nullptr); return success; } template<class R, class P, class Function, class I, class... Args> typename std::invoke_result<Function, I *, Args...>::type timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func, Args &&... args) { using ::android::hardware::Status; // Execute on a background thread but do not defer execution. auto future = std::async(std::launch::async, func, interfaceObject, std::forward<Args>(args)...); auto status = future.wait_for(wait); if (status == std::future_status::ready) { return future.get(); } // This future belongs to a background thread that we no longer care about. // Putting this in the global list avoids std::future::~future() that may wait for the // result to come back. // This leaks memory, but lshal is a debugging tool, so this is fine. static std::vector<decltype(future)> gDeadPool{}; gDeadPool.emplace_back(std::move(future)); if (status == std::future_status::timeout) { typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()}; auto boundFunc = std::bind(std::forward<Function>(func), interfaceObject.get(), std::forward<Args>(args)...); bool success = timeout(wait, [&ret, &boundFunc] { ret = std::move(boundFunc()); }); if (!success) { return Status::fromStatusT(TIMED_OUT); } return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE, "Illegal future_status"); return ret; } } // namespace lshal } // namespace android cmds/lshal/main.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,5 @@ int main(int argc, char **argv) { using namespace ::android::lshal; // Use _exit() to force terminate background threads in Timeout.h _exit(Lshal{}.main(Arg{argc, argv})); return Lshal{}.main(Arg{argc, argv}); } cmds/lshal/test.cpp +7 −115 Original line number Diff line number Diff line Loading @@ -14,10 +14,6 @@ * limitations under the License. */ #include <chrono> #include <future> #include <mutex> #include "android/hidl/base/1.0/IBase.h" #define LOG_TAG "Lshal" #include <android-base/logging.h> Loading @@ -40,8 +36,6 @@ using namespace testing; using std::chrono_literals::operator""ms; using ::android::hidl::base::V1_0::DebugInfo; using ::android::hidl::base::V1_0::IBase; using ::android::hidl::manager::V1_0::IServiceManager; Loading Loading @@ -940,7 +934,10 @@ TEST_F(ListTest, DumpDebug) { return hardware::Void(); })); EXPECT_CALL(*serviceManager, get(_, _)) .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> { .WillRepeatedly( Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> { int id = getIdFromInstanceName(instance); if (id > inheritanceLevel) return nullptr; return sp<IBase>(service); })); Loading @@ -960,110 +957,6 @@ TEST_F(ListTest, DumpDebug) { EXPECT_EQ("", err.str()); } // In SlowService, everything goes slooooooow. Each IPC call will wait for // the specified time before calling the callback function or returning. class SlowService : public IBase { public: explicit SlowService(std::chrono::milliseconds wait) : mWait(wait) {} android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override { std::this_thread::sleep_for(mWait); cb(getInterfaceName(1)); storeHistory("interfaceDescriptor"); return hardware::Void(); } android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override { std::this_thread::sleep_for(mWait); std::vector<hidl_string> ret; ret.push_back(getInterfaceName(1)); ret.push_back(IBase::descriptor); cb(ret); storeHistory("interfaceChain"); return hardware::Void(); } android::hardware::Return<void> getHashChain(getHashChain_cb cb) override { std::this_thread::sleep_for(mWait); std::vector<hidl_hash> ret; ret.push_back(getHashFromId(0)); ret.push_back(getHashFromId(0xff)); cb(ret); storeHistory("getHashChain"); return hardware::Void(); } android::hardware::Return<void> debug(const hidl_handle&, const hidl_vec<hidl_string>&) override { std::this_thread::sleep_for(mWait); storeHistory("debug"); return Void(); } template <class R, class P, class Pred> bool waitForHistory(std::chrono::duration<R, P> wait, Pred predicate) { std::unique_lock<std::mutex> lock(mLock); return mCv.wait_for(lock, wait, [&]() { return predicate(mCallHistory); }); } private: void storeHistory(std::string hist) { { std::lock_guard<std::mutex> lock(mLock); mCallHistory.emplace_back(std::move(hist)); } mCv.notify_all(); } const std::chrono::milliseconds mWait; std::mutex mLock; std::condition_variable mCv; // List of functions that have finished being called on this interface. std::vector<std::string> mCallHistory; }; class TimeoutTest : public ListTest { public: void setMockServiceManager(sp<IBase> service) { EXPECT_CALL(*serviceManager, list(_)) .WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) { std::vector<hidl_string> ret; ret.push_back(getInterfaceName(1) + "/default"); cb(ret); return hardware::Void(); })); EXPECT_CALL(*serviceManager, get(_, _)) .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> { return service; })); } }; TEST_F(TimeoutTest, BackgroundThreadIsKept) { auto lshalIpcTimeout = 100ms; auto serviceIpcTimeout = 200ms; lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout); sp<SlowService> service = new SlowService(serviceIpcTimeout); setMockServiceManager(service); optind = 1; // mimic Lshal::parseArg() EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"}))); EXPECT_THAT(err.str(), HasSubstr("Skipping \"a.h.foo1@1.0::IFoo/default\"")); EXPECT_TRUE(service->waitForHistory(serviceIpcTimeout * 5, [](const auto& hist) { return hist.size() == 1 && hist[0] == "interfaceChain"; })) << "The background thread should continue after the main thread moves on, but it is killed"; } TEST_F(TimeoutTest, BackgroundThreadDoesNotBlockMainThread) { auto lshalIpcTimeout = 100ms; auto serviceIpcTimeout = 2000ms; auto start = std::chrono::system_clock::now(); lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout); sp<SlowService> service = new SlowService(serviceIpcTimeout); setMockServiceManager(service); optind = 1; // mimic Lshal::parseArg() EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"}))); EXPECT_LE(std::chrono::system_clock::now(), start + 5 * lshalIpcTimeout) << "The main thread should not be blocked by the background task"; } class ListVintfTest : public ListTest { public: virtual void SetUp() override { Loading Loading @@ -1186,6 +1079,5 @@ TEST_F(HelpTest, UnknownOptionHelp2) { int main(int argc, char **argv) { ::testing::InitGoogleMock(&argc, argv); // Use _exit() to force terminate background threads in Timeout.h _exit(RUN_ALL_TESTS()); return RUN_ALL_TESTS(); } include/input/InputDevice.h +17 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,17 @@ struct InputDeviceIdentifier { bool operator!=(const InputDeviceIdentifier&) const = default; }; /** * Holds View related behaviors for an InputDevice. */ struct InputDeviceViewBehavior { /** * The smooth scroll behavior that applies for all source/axis, if defined by the device. * Empty optional if the device has not specified the default smooth scroll behavior. */ std::optional<bool> shouldSmoothScroll; }; /* Types of input device sensors. Keep sync with core/java/android/hardware/Sensor.java */ enum class InputDeviceSensorType : int32_t { ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, Loading Loading @@ -266,7 +277,8 @@ public: void initialize(int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, bool hasMic, int32_t associatedDisplayId); bool isExternal, bool hasMic, int32_t associatedDisplayId, InputDeviceViewBehavior viewBehavior = {{}}); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } Loading Loading @@ -298,6 +310,8 @@ public: return mKeyboardLayoutInfo; } inline const InputDeviceViewBehavior& getViewBehavior() const { return mViewBehavior; } inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) { mKeyCharacterMap = value; } Loading Loading @@ -359,6 +373,8 @@ private: std::unordered_map<int32_t, InputDeviceLightInfo> mLights; /* Map from battery ID to battery info */ std::unordered_map<int32_t, InputDeviceBatteryInfo> mBatteries; /** The View related behaviors for the device. */ InputDeviceViewBehavior mViewBehavior; }; /* Types of input device configuration files. */ Loading Loading
cmds/dumpstate/dumpstate.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -1563,6 +1563,13 @@ static void DumpstateLimitedOnly() { RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"}); RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"}); printf("========================================================\n"); printf("== ANR Traces\n"); printf("========================================================\n"); AddAnrTraceFiles(); printf("========================================================\n"); printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(), ds.progress_->GetMax(), ds.progress_->GetInitialMax()); Loading
cmds/lshal/Timeout.h +65 −26 Original line number Diff line number Diff line Loading @@ -16,44 +16,83 @@ #pragma once #include <condition_variable> #include <chrono> #include <future> #include <functional> #include <mutex> #include <thread> #include <hidl/Status.h> #include <utils/Errors.h> namespace android { namespace lshal { // Call function on interfaceObject and wait for result until the given timeout has reached. // Callback functions pass to timeoutIPC() may be executed after the this function // has returned, especially if deadline has been reached. Hence, care must be taken when passing // data between the background thread and the main thread. See b/311143089. class BackgroundTaskState { public: explicit BackgroundTaskState(std::function<void(void)> &&func) : mFunc(std::forward<decltype(func)>(func)) {} void notify() { std::unique_lock<std::mutex> lock(mMutex); mFinished = true; lock.unlock(); mCondVar.notify_all(); } template<class C, class D> bool wait(std::chrono::time_point<C, D> end) { std::unique_lock<std::mutex> lock(mMutex); mCondVar.wait_until(lock, end, [this](){ return this->mFinished; }); return mFinished; } void operator()() { mFunc(); } private: std::mutex mMutex; std::condition_variable mCondVar; bool mFinished = false; std::function<void(void)> mFunc; }; void *callAndNotify(void *data) { BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data); state(); state.notify(); return nullptr; } template<class R, class P> bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) { auto now = std::chrono::system_clock::now(); BackgroundTaskState state{std::forward<decltype(func)>(func)}; pthread_t thread; if (pthread_create(&thread, nullptr, callAndNotify, &state)) { std::cerr << "FATAL: could not create background thread." << std::endl; return false; } bool success = state.wait(now + delay); if (!success) { pthread_kill(thread, SIGINT); } pthread_join(thread, nullptr); return success; } template<class R, class P, class Function, class I, class... Args> typename std::invoke_result<Function, I *, Args...>::type timeoutIPC(std::chrono::duration<R, P> wait, const sp<I> &interfaceObject, Function &&func, Args &&... args) { using ::android::hardware::Status; // Execute on a background thread but do not defer execution. auto future = std::async(std::launch::async, func, interfaceObject, std::forward<Args>(args)...); auto status = future.wait_for(wait); if (status == std::future_status::ready) { return future.get(); } // This future belongs to a background thread that we no longer care about. // Putting this in the global list avoids std::future::~future() that may wait for the // result to come back. // This leaks memory, but lshal is a debugging tool, so this is fine. static std::vector<decltype(future)> gDeadPool{}; gDeadPool.emplace_back(std::move(future)); if (status == std::future_status::timeout) { typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()}; auto boundFunc = std::bind(std::forward<Function>(func), interfaceObject.get(), std::forward<Args>(args)...); bool success = timeout(wait, [&ret, &boundFunc] { ret = std::move(boundFunc()); }); if (!success) { return Status::fromStatusT(TIMED_OUT); } return Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE, "Illegal future_status"); return ret; } } // namespace lshal } // namespace android
cmds/lshal/main.cpp +1 −2 Original line number Diff line number Diff line Loading @@ -18,6 +18,5 @@ int main(int argc, char **argv) { using namespace ::android::lshal; // Use _exit() to force terminate background threads in Timeout.h _exit(Lshal{}.main(Arg{argc, argv})); return Lshal{}.main(Arg{argc, argv}); }
cmds/lshal/test.cpp +7 −115 Original line number Diff line number Diff line Loading @@ -14,10 +14,6 @@ * limitations under the License. */ #include <chrono> #include <future> #include <mutex> #include "android/hidl/base/1.0/IBase.h" #define LOG_TAG "Lshal" #include <android-base/logging.h> Loading @@ -40,8 +36,6 @@ using namespace testing; using std::chrono_literals::operator""ms; using ::android::hidl::base::V1_0::DebugInfo; using ::android::hidl::base::V1_0::IBase; using ::android::hidl::manager::V1_0::IServiceManager; Loading Loading @@ -940,7 +934,10 @@ TEST_F(ListTest, DumpDebug) { return hardware::Void(); })); EXPECT_CALL(*serviceManager, get(_, _)) .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> { .WillRepeatedly( Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> { int id = getIdFromInstanceName(instance); if (id > inheritanceLevel) return nullptr; return sp<IBase>(service); })); Loading @@ -960,110 +957,6 @@ TEST_F(ListTest, DumpDebug) { EXPECT_EQ("", err.str()); } // In SlowService, everything goes slooooooow. Each IPC call will wait for // the specified time before calling the callback function or returning. class SlowService : public IBase { public: explicit SlowService(std::chrono::milliseconds wait) : mWait(wait) {} android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override { std::this_thread::sleep_for(mWait); cb(getInterfaceName(1)); storeHistory("interfaceDescriptor"); return hardware::Void(); } android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override { std::this_thread::sleep_for(mWait); std::vector<hidl_string> ret; ret.push_back(getInterfaceName(1)); ret.push_back(IBase::descriptor); cb(ret); storeHistory("interfaceChain"); return hardware::Void(); } android::hardware::Return<void> getHashChain(getHashChain_cb cb) override { std::this_thread::sleep_for(mWait); std::vector<hidl_hash> ret; ret.push_back(getHashFromId(0)); ret.push_back(getHashFromId(0xff)); cb(ret); storeHistory("getHashChain"); return hardware::Void(); } android::hardware::Return<void> debug(const hidl_handle&, const hidl_vec<hidl_string>&) override { std::this_thread::sleep_for(mWait); storeHistory("debug"); return Void(); } template <class R, class P, class Pred> bool waitForHistory(std::chrono::duration<R, P> wait, Pred predicate) { std::unique_lock<std::mutex> lock(mLock); return mCv.wait_for(lock, wait, [&]() { return predicate(mCallHistory); }); } private: void storeHistory(std::string hist) { { std::lock_guard<std::mutex> lock(mLock); mCallHistory.emplace_back(std::move(hist)); } mCv.notify_all(); } const std::chrono::milliseconds mWait; std::mutex mLock; std::condition_variable mCv; // List of functions that have finished being called on this interface. std::vector<std::string> mCallHistory; }; class TimeoutTest : public ListTest { public: void setMockServiceManager(sp<IBase> service) { EXPECT_CALL(*serviceManager, list(_)) .WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) { std::vector<hidl_string> ret; ret.push_back(getInterfaceName(1) + "/default"); cb(ret); return hardware::Void(); })); EXPECT_CALL(*serviceManager, get(_, _)) .WillRepeatedly(Invoke([&](const hidl_string&, const hidl_string&) -> sp<IBase> { return service; })); } }; TEST_F(TimeoutTest, BackgroundThreadIsKept) { auto lshalIpcTimeout = 100ms; auto serviceIpcTimeout = 200ms; lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout); sp<SlowService> service = new SlowService(serviceIpcTimeout); setMockServiceManager(service); optind = 1; // mimic Lshal::parseArg() EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"}))); EXPECT_THAT(err.str(), HasSubstr("Skipping \"a.h.foo1@1.0::IFoo/default\"")); EXPECT_TRUE(service->waitForHistory(serviceIpcTimeout * 5, [](const auto& hist) { return hist.size() == 1 && hist[0] == "interfaceChain"; })) << "The background thread should continue after the main thread moves on, but it is killed"; } TEST_F(TimeoutTest, BackgroundThreadDoesNotBlockMainThread) { auto lshalIpcTimeout = 100ms; auto serviceIpcTimeout = 2000ms; auto start = std::chrono::system_clock::now(); lshal->setWaitTimeForTest(lshalIpcTimeout, lshalIpcTimeout); sp<SlowService> service = new SlowService(serviceIpcTimeout); setMockServiceManager(service); optind = 1; // mimic Lshal::parseArg() EXPECT_NE(0u, mockList->main(createArg({"lshal", "--types=b", "-i", "--neat"}))); EXPECT_LE(std::chrono::system_clock::now(), start + 5 * lshalIpcTimeout) << "The main thread should not be blocked by the background task"; } class ListVintfTest : public ListTest { public: virtual void SetUp() override { Loading Loading @@ -1186,6 +1079,5 @@ TEST_F(HelpTest, UnknownOptionHelp2) { int main(int argc, char **argv) { ::testing::InitGoogleMock(&argc, argv); // Use _exit() to force terminate background threads in Timeout.h _exit(RUN_ALL_TESTS()); return RUN_ALL_TESTS(); }
include/input/InputDevice.h +17 −1 Original line number Diff line number Diff line Loading @@ -75,6 +75,17 @@ struct InputDeviceIdentifier { bool operator!=(const InputDeviceIdentifier&) const = default; }; /** * Holds View related behaviors for an InputDevice. */ struct InputDeviceViewBehavior { /** * The smooth scroll behavior that applies for all source/axis, if defined by the device. * Empty optional if the device has not specified the default smooth scroll behavior. */ std::optional<bool> shouldSmoothScroll; }; /* Types of input device sensors. Keep sync with core/java/android/hardware/Sensor.java */ enum class InputDeviceSensorType : int32_t { ACCELEROMETER = ASENSOR_TYPE_ACCELEROMETER, Loading Loading @@ -266,7 +277,8 @@ public: void initialize(int32_t id, int32_t generation, int32_t controllerNumber, const InputDeviceIdentifier& identifier, const std::string& alias, bool isExternal, bool hasMic, int32_t associatedDisplayId); bool isExternal, bool hasMic, int32_t associatedDisplayId, InputDeviceViewBehavior viewBehavior = {{}}); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } Loading Loading @@ -298,6 +310,8 @@ public: return mKeyboardLayoutInfo; } inline const InputDeviceViewBehavior& getViewBehavior() const { return mViewBehavior; } inline void setKeyCharacterMap(const std::shared_ptr<KeyCharacterMap> value) { mKeyCharacterMap = value; } Loading Loading @@ -359,6 +373,8 @@ private: std::unordered_map<int32_t, InputDeviceLightInfo> mLights; /* Map from battery ID to battery info */ std::unordered_map<int32_t, InputDeviceBatteryInfo> mBatteries; /** The View related behaviors for the device. */ InputDeviceViewBehavior mViewBehavior; }; /* Types of input device configuration files. */ Loading