1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "wake_lock_manager.h" 18 19 #include <base/bind.h> 20 #include <base/files/file_util.h> 21 #include <base/format_macros.h> 22 #include <base/logging.h> 23 #include <base/strings/stringprintf.h> 24 #include <binder/IBinder.h> 25 #include <binderwrapper/binder_wrapper.h> 26 27 namespace android { 28 namespace { 29 30 // Paths to the sysfs lock and unlock files. 31 const char kLockPath[] = "/sys/power/wake_lock"; 32 const char kUnlockPath[] = "/sys/power/wake_unlock"; 33 34 // Writes |data| to |path|, returning true on success or logging an error and 35 // returning false otherwise. 36 bool WriteToFile(const base::FilePath& path, const std::string& data) { 37 // This are sysfs "files" in real life, so it doesn't matter if we overwrite 38 // them or append to them, but appending makes it easier for tests to detect 39 // multiple writes when using real temporary files. 40 VLOG(1) << "Writing \"" << data << "\" to " << path.value(); 41 if (!base::AppendToFile(path, data.data(), data.size())) { 42 PLOG(ERROR) << "Failed to write \"" << data << "\" to " << path.value(); 43 return false; 44 } 45 return true; 46 } 47 48 } // namespace 49 50 const char WakeLockManager::kLockName[] = "nativepowerman"; 51 52 WakeLockManager::Request::Request(const std::string& tag, 53 const std::string& package, 54 uid_t uid) 55 : tag(tag), 56 package(package), 57 uid(uid) {} 58 59 WakeLockManager::Request::Request(const Request& request) = default; 60 61 WakeLockManager::Request::Request() : uid(-1) {} 62 63 WakeLockManager::WakeLockManager() 64 : lock_path_(kLockPath), 65 unlock_path_(kUnlockPath) {} 66 67 WakeLockManager::~WakeLockManager() { 68 while (!requests_.empty()) 69 RemoveRequest(requests_.begin()->first); 70 } 71 72 bool WakeLockManager::Init() { 73 if (!base::PathIsWritable(lock_path_) || 74 !base::PathIsWritable(unlock_path_)) { 75 LOG(ERROR) << lock_path_.value() << " and/or " << unlock_path_.value() 76 << " are not writable"; 77 return false; 78 } 79 return true; 80 } 81 82 bool WakeLockManager::AddRequest(sp<IBinder> client_binder, 83 const std::string& tag, 84 const std::string& package, 85 uid_t uid) { 86 const bool new_request = !requests_.count(client_binder); 87 LOG(INFO) << (new_request ? "Adding" : "Updating") << " request for binder " 88 << client_binder.get() << ": tag=\"" << tag << "\"" 89 << " package=\"" << package << "\" uid=" << uid; 90 91 const bool first_request = requests_.empty(); 92 93 if (new_request) { 94 if (!BinderWrapper::Get()->RegisterForDeathNotifications( 95 client_binder, 96 base::Bind(&WakeLockManager::HandleBinderDeath, 97 base::Unretained(this), client_binder))) { 98 return false; 99 } 100 } 101 requests_[client_binder] = Request(tag, package, uid); 102 103 if (first_request && !WriteToFile(lock_path_, kLockName)) 104 return false; 105 106 return true; 107 } 108 109 bool WakeLockManager::RemoveRequest(sp<IBinder> client_binder) { 110 LOG(INFO) << "Removing request for binder " << client_binder.get(); 111 112 if (!requests_.erase(client_binder)) { 113 LOG(WARNING) << "Ignoring removal request for unknown binder " 114 << client_binder.get(); 115 return false; 116 } 117 BinderWrapper::Get()->UnregisterForDeathNotifications(client_binder); 118 119 if (requests_.empty() && !WriteToFile(unlock_path_, kLockName)) 120 return false; 121 122 return true; 123 } 124 125 void WakeLockManager::HandleBinderDeath(sp<IBinder> binder) { 126 LOG(INFO) << "Received death notification for binder " << binder.get(); 127 RemoveRequest(binder); 128 } 129 130 } // namespace android 131