| /* |
| * Copyright (C) 2015 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 "wake_lock_manager.h" |
| |
| #include <base/bind.h> |
| #include <base/files/file_util.h> |
| #include <base/format_macros.h> |
| #include <base/logging.h> |
| #include <base/strings/stringprintf.h> |
| #include <binder/IBinder.h> |
| #include <binderwrapper/binder_wrapper.h> |
| |
| namespace android { |
| namespace { |
| |
| // Paths to the sysfs lock and unlock files. |
| const char kLockPath[] = "/sys/power/wake_lock"; |
| const char kUnlockPath[] = "/sys/power/wake_unlock"; |
| |
| // Writes |data| to |path|, returning true on success or logging an error and |
| // returning false otherwise. |
| bool WriteToFile(const base::FilePath& path, const std::string& data) { |
| // This are sysfs "files" in real life, so it doesn't matter if we overwrite |
| // them or append to them, but appending makes it easier for tests to detect |
| // multiple writes when using real temporary files. |
| VLOG(1) << "Writing \"" << data << "\" to " << path.value(); |
| if (!base::AppendToFile(path, data.data(), data.size())) { |
| PLOG(ERROR) << "Failed to write \"" << data << "\" to " << path.value(); |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| const char WakeLockManager::kLockName[] = "nativepowerman"; |
| |
| WakeLockManager::Request::Request(const std::string& tag, |
| const std::string& package, |
| uid_t uid) |
| : tag(tag), |
| package(package), |
| uid(uid) {} |
| |
| WakeLockManager::Request::Request(const Request& request) = default; |
| |
| WakeLockManager::Request::Request() : uid(-1) {} |
| |
| WakeLockManager::WakeLockManager() |
| : lock_path_(kLockPath), |
| unlock_path_(kUnlockPath) {} |
| |
| WakeLockManager::~WakeLockManager() { |
| while (!requests_.empty()) |
| RemoveRequest(requests_.begin()->first); |
| } |
| |
| bool WakeLockManager::Init() { |
| if (!base::PathIsWritable(lock_path_) || |
| !base::PathIsWritable(unlock_path_)) { |
| LOG(ERROR) << lock_path_.value() << " and/or " << unlock_path_.value() |
| << " are not writable"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool WakeLockManager::AddRequest(sp<IBinder> client_binder, |
| const std::string& tag, |
| const std::string& package, |
| uid_t uid) { |
| const bool new_request = !requests_.count(client_binder); |
| LOG(INFO) << (new_request ? "Adding" : "Updating") << " request for binder " |
| << client_binder.get() << ": tag=\"" << tag << "\"" |
| << " package=\"" << package << "\" uid=" << uid; |
| |
| const bool first_request = requests_.empty(); |
| |
| if (new_request) { |
| if (!BinderWrapper::Get()->RegisterForDeathNotifications( |
| client_binder, |
| base::Bind(&WakeLockManager::HandleBinderDeath, |
| base::Unretained(this), client_binder))) { |
| return false; |
| } |
| } |
| requests_[client_binder] = Request(tag, package, uid); |
| |
| if (first_request && !WriteToFile(lock_path_, kLockName)) |
| return false; |
| |
| return true; |
| } |
| |
| bool WakeLockManager::RemoveRequest(sp<IBinder> client_binder) { |
| LOG(INFO) << "Removing request for binder " << client_binder.get(); |
| |
| if (!requests_.erase(client_binder)) { |
| LOG(WARNING) << "Ignoring removal request for unknown binder " |
| << client_binder.get(); |
| return false; |
| } |
| BinderWrapper::Get()->UnregisterForDeathNotifications(client_binder); |
| |
| if (requests_.empty() && !WriteToFile(unlock_path_, kLockName)) |
| return false; |
| |
| return true; |
| } |
| |
| void WakeLockManager::HandleBinderDeath(sp<IBinder> binder) { |
| LOG(INFO) << "Received death notification for binder " << binder.get(); |
| RemoveRequest(binder); |
| } |
| |
| } // namespace android |