RAII style wakelocks: Add tryGet() factory method.
Wakelock acquisition can fail if suspend service is not available. Make this clear by returning an optional value that client must check before entering wakelock critical sections. Bug: b/179229598 Test: Boot test on Pixel 4 device Change-Id: Ied00fa919c20d8a30f1c40ee34a91a2a7e240689
This commit is contained in:
parent
1da7880c26
commit
d8da2af1e5
4 changed files with 45 additions and 8 deletions
|
@ -34,7 +34,11 @@ int main(int argc, char ** /* argv */) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
android::wakelock::WakeLock wl{gWakeLockName}; // RAII object
|
||||
auto wl = android::wakelock::WakeLock::tryGet(gWakeLockName); // RAII object
|
||||
if (!wl.has_value()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while (true) { sleep(1000000); };
|
||||
std::abort(); // should never reach here
|
||||
return 0;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
|
@ -24,13 +25,17 @@ namespace wakelock {
|
|||
|
||||
// RAII-style wake lock implementation
|
||||
class WakeLock {
|
||||
public:
|
||||
WakeLock(const std::string& name);
|
||||
~WakeLock();
|
||||
|
||||
private:
|
||||
class WakeLockImpl;
|
||||
std::unique_ptr<WakeLockImpl> mImpl;
|
||||
|
||||
public:
|
||||
static std::optional<WakeLock> tryGet(const std::string& name);
|
||||
// Constructor is only made public for use with std::optional.
|
||||
// It is not intended to be and cannot be invoked from public context,
|
||||
// since private WakeLockImpl prevents calling the constructor directly.
|
||||
WakeLock(std::unique_ptr<WakeLockImpl> wlImpl);
|
||||
~WakeLock();
|
||||
};
|
||||
|
||||
} // namespace wakelock
|
||||
|
|
29
power.cpp
29
power.cpp
|
@ -88,26 +88,51 @@ class WakeLock::WakeLockImpl {
|
|||
public:
|
||||
WakeLockImpl(const std::string& name);
|
||||
~WakeLockImpl();
|
||||
bool acquireOk();
|
||||
|
||||
private:
|
||||
sp<IWakeLock> mWakeLock;
|
||||
};
|
||||
|
||||
WakeLock::WakeLock(const std::string& name) : mImpl(std::make_unique<WakeLockImpl>(name)) {}
|
||||
std::optional<WakeLock> WakeLock::tryGet(const std::string& name) {
|
||||
std::unique_ptr<WakeLockImpl> wlImpl = std::make_unique<WakeLockImpl>(name);
|
||||
if (wlImpl->acquireOk()) {
|
||||
return { std::move(wlImpl) };
|
||||
} else {
|
||||
LOG(ERROR) << "Failed to acquire wakelock: " << name;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
WakeLock::WakeLock(std::unique_ptr<WakeLockImpl> wlImpl) : mImpl(std::move(wlImpl)) {}
|
||||
|
||||
WakeLock::~WakeLock() = default;
|
||||
|
||||
WakeLock::WakeLockImpl::WakeLockImpl(const std::string& name) : mWakeLock(nullptr) {
|
||||
static sp<ISystemSuspend> suspendService = ISystemSuspend::getService();
|
||||
mWakeLock = suspendService->acquireWakeLock(WakeLockType::PARTIAL, name);
|
||||
auto ret = suspendService->acquireWakeLock(WakeLockType::PARTIAL, name);
|
||||
// It's possible that during device SystemSuspend service is not avaiable. In these
|
||||
// situations HIDL calls to it will result in a DEAD_OBJECT transaction error.
|
||||
if (ret.isDeadObject()) {
|
||||
LOG(ERROR) << "ISuspendService::acquireWakeLock() call failed: " << ret.description();
|
||||
} else {
|
||||
mWakeLock = ret;
|
||||
}
|
||||
}
|
||||
|
||||
WakeLock::WakeLockImpl::~WakeLockImpl() {
|
||||
if (!acquireOk()) {
|
||||
return;
|
||||
}
|
||||
auto ret = mWakeLock->release();
|
||||
if (!ret.isOk()) {
|
||||
LOG(ERROR) << "IWakeLock::release() call failed: " << ret.description();
|
||||
}
|
||||
}
|
||||
|
||||
bool WakeLock::WakeLockImpl::acquireOk() {
|
||||
return mWakeLock != nullptr;
|
||||
}
|
||||
|
||||
} // namespace wakelock
|
||||
} // namespace android
|
||||
|
|
|
@ -121,7 +121,10 @@ class WakeLockTest : public ::testing::Test {
|
|||
TEST_F(WakeLockTest, WakeLockDestructor) {
|
||||
auto name = std::to_string(rand());
|
||||
{
|
||||
android::wakelock::WakeLock wl{name};
|
||||
auto wl = android::wakelock::WakeLock::tryGet(name);
|
||||
if (!wl.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WakeLockInfo info;
|
||||
auto success = findWakeLockInfoByName(controlService, name, &info);
|
||||
|
|
Loading…
Reference in a new issue