| // |
| // 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 "shill/dbus/chromeos_power_manager_proxy.h" |
| |
| #include <base/bind.h> |
| #include <google/protobuf/message_lite.h> |
| |
| #include "power_manager/proto_bindings/suspend.pb.h" |
| #include "shill/event_dispatcher.h" |
| #include "shill/logging.h" |
| |
| using std::string; |
| using std::vector; |
| |
| namespace shill { |
| |
| namespace { |
| |
| // Serializes |protobuf| to |out| and returns true on success. |
| bool SerializeProtocolBuffer(const google::protobuf::MessageLite& protobuf, |
| vector<uint8_t>* out) { |
| CHECK(out); |
| out->clear(); |
| string serialized_protobuf; |
| if (!protobuf.SerializeToString(&serialized_protobuf)) |
| return false; |
| out->assign(serialized_protobuf.begin(), serialized_protobuf.end()); |
| return true; |
| } |
| |
| // Deserializes |serialized_protobuf| to |protobuf_out| and returns true on |
| // success. |
| bool DeserializeProtocolBuffer(const vector<uint8_t>& serialized_protobuf, |
| google::protobuf::MessageLite* protobuf_out) { |
| CHECK(protobuf_out); |
| if (serialized_protobuf.empty()) |
| return false; |
| return protobuf_out->ParseFromArray(&serialized_protobuf.front(), |
| serialized_protobuf.size()); |
| } |
| |
| } // namespace |
| |
| ChromeosPowerManagerProxy::ChromeosPowerManagerProxy( |
| EventDispatcher* dispatcher, |
| const scoped_refptr<dbus::Bus>& bus, |
| PowerManagerProxyDelegate* delegate, |
| const base::Closure& service_appeared_callback, |
| const base::Closure& service_vanished_callback) |
| : proxy_(new org::chromium::PowerManagerProxy(bus)), |
| dispatcher_(dispatcher), |
| delegate_(delegate), |
| service_appeared_callback_(service_appeared_callback), |
| service_vanished_callback_(service_vanished_callback) { |
| // Register signal handlers. |
| proxy_->RegisterSuspendImminentSignalHandler( |
| base::Bind(&ChromeosPowerManagerProxy::SuspendImminent, |
| weak_factory_.GetWeakPtr()), |
| base::Bind(&ChromeosPowerManagerProxy::OnSignalConnected, |
| weak_factory_.GetWeakPtr())); |
| proxy_->RegisterSuspendDoneSignalHandler( |
| base::Bind(&ChromeosPowerManagerProxy::SuspendDone, |
| weak_factory_.GetWeakPtr()), |
| base::Bind(&ChromeosPowerManagerProxy::OnSignalConnected, |
| weak_factory_.GetWeakPtr())); |
| proxy_->RegisterDarkSuspendImminentSignalHandler( |
| base::Bind(&ChromeosPowerManagerProxy::DarkSuspendImminent, |
| weak_factory_.GetWeakPtr()), |
| base::Bind(&ChromeosPowerManagerProxy::OnSignalConnected, |
| weak_factory_.GetWeakPtr())); |
| |
| // One time callback when service becomes available. |
| proxy_->GetObjectProxy()->WaitForServiceToBeAvailable( |
| base::Bind(&ChromeosPowerManagerProxy::OnServiceAvailable, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| ChromeosPowerManagerProxy::~ChromeosPowerManagerProxy() {} |
| |
| bool ChromeosPowerManagerProxy::RegisterSuspendDelay( |
| base::TimeDelta timeout, |
| const string& description, |
| int* delay_id_out) { |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| return RegisterSuspendDelayInternal(false, |
| timeout, |
| description, |
| delay_id_out); |
| } |
| |
| bool ChromeosPowerManagerProxy::UnregisterSuspendDelay(int delay_id) { |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| return UnregisterSuspendDelayInternal(false, delay_id); |
| } |
| |
| bool ChromeosPowerManagerProxy::ReportSuspendReadiness(int delay_id, |
| int suspend_id) { |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| return ReportSuspendReadinessInternal(false, delay_id, suspend_id); |
| } |
| |
| bool ChromeosPowerManagerProxy::RegisterDarkSuspendDelay( |
| base::TimeDelta timeout, |
| const string& description, |
| int* delay_id_out) { |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| return RegisterSuspendDelayInternal(true, |
| timeout, |
| description, |
| delay_id_out); |
| } |
| |
| bool ChromeosPowerManagerProxy::UnregisterDarkSuspendDelay(int delay_id) { |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| return UnregisterSuspendDelayInternal(true, delay_id); |
| } |
| |
| bool ChromeosPowerManagerProxy::ReportDarkSuspendReadiness(int delay_id, |
| int suspend_id ) { |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| return ReportSuspendReadinessInternal(true, delay_id, suspend_id); |
| } |
| |
| bool ChromeosPowerManagerProxy::RecordDarkResumeWakeReason( |
| const string& wake_reason) { |
| LOG(INFO) << __func__; |
| |
| if (!service_available_) { |
| LOG(ERROR) << "PowerManager service not available"; |
| return false; |
| } |
| |
| power_manager::DarkResumeWakeReason proto; |
| proto.set_wake_reason(wake_reason); |
| vector<uint8_t> serialized_proto; |
| CHECK(SerializeProtocolBuffer(proto, &serialized_proto)); |
| |
| brillo::ErrorPtr error; |
| if (!proxy_->RecordDarkResumeWakeReason(serialized_proto, &error)) { |
| LOG(ERROR) << "Failed tp record dark resume wake reason: " |
| << error->GetCode() << " " << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool ChromeosPowerManagerProxy::RegisterSuspendDelayInternal( |
| bool is_dark, |
| base::TimeDelta timeout, |
| const string& description, |
| int* delay_id_out) { |
| const string is_dark_arg = (is_dark ? "dark=true" : "dark=false"); |
| LOG(INFO) << __func__ << "(" << timeout.InMilliseconds() |
| << ", " << is_dark_arg <<")"; |
| |
| power_manager::RegisterSuspendDelayRequest request_proto; |
| request_proto.set_timeout(timeout.ToInternalValue()); |
| request_proto.set_description(description); |
| vector<uint8_t> serialized_request; |
| CHECK(SerializeProtocolBuffer(request_proto, &serialized_request)); |
| |
| vector<uint8_t> serialized_reply; |
| brillo::ErrorPtr error; |
| if (is_dark) { |
| proxy_->RegisterDarkSuspendDelay(serialized_request, |
| &serialized_reply, |
| &error); |
| } else { |
| proxy_->RegisterSuspendDelay(serialized_request, &serialized_reply, &error); |
| } |
| if (error) { |
| LOG(ERROR) << "Failed to register suspend delay: " |
| << error->GetCode() << " " << error->GetMessage(); |
| return false; |
| } |
| |
| power_manager::RegisterSuspendDelayReply reply_proto; |
| if (!DeserializeProtocolBuffer(serialized_reply, &reply_proto)) { |
| LOG(ERROR) << "Failed to register " |
| << (is_dark ? "dark " : "") |
| << "suspend delay. Couldn't parse response."; |
| return false; |
| } |
| *delay_id_out = reply_proto.delay_id(); |
| return true; |
| } |
| |
| bool ChromeosPowerManagerProxy::UnregisterSuspendDelayInternal(bool is_dark, |
| int delay_id) { |
| const string is_dark_arg = (is_dark ? "dark=true" : "dark=false"); |
| LOG(INFO) << __func__ << "(" << delay_id << ", " << is_dark_arg << ")"; |
| |
| power_manager::UnregisterSuspendDelayRequest request_proto; |
| request_proto.set_delay_id(delay_id); |
| vector<uint8_t> serialized_request; |
| CHECK(SerializeProtocolBuffer(request_proto, &serialized_request)); |
| |
| brillo::ErrorPtr error; |
| if (is_dark) { |
| proxy_->UnregisterDarkSuspendDelay(serialized_request, &error); |
| } else { |
| proxy_->UnregisterSuspendDelay(serialized_request, &error); |
| } |
| if (error) { |
| LOG(ERROR) << "Failed to unregister suspend delay: " |
| << error->GetCode() << " " << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| bool ChromeosPowerManagerProxy::ReportSuspendReadinessInternal( |
| bool is_dark, int delay_id, int suspend_id) { |
| const string is_dark_arg = (is_dark ? "dark=true" : "dark=false"); |
| LOG(INFO) << __func__ |
| << "(" << delay_id |
| << ", " << suspend_id |
| << ", " << is_dark_arg << ")"; |
| |
| power_manager::SuspendReadinessInfo proto; |
| proto.set_delay_id(delay_id); |
| proto.set_suspend_id(suspend_id); |
| vector<uint8_t> serialized_proto; |
| CHECK(SerializeProtocolBuffer(proto, &serialized_proto)); |
| |
| brillo::ErrorPtr error; |
| if (is_dark) { |
| proxy_->HandleDarkSuspendReadiness(serialized_proto, &error); |
| } else { |
| proxy_->HandleSuspendReadiness(serialized_proto, &error); |
| } |
| if (error) { |
| LOG(ERROR) << "Failed to report suspend readiness: " |
| << error->GetCode() << " " << error->GetMessage(); |
| return false; |
| } |
| return true; |
| } |
| |
| void ChromeosPowerManagerProxy::SuspendImminent( |
| const vector<uint8_t>& serialized_proto) { |
| LOG(INFO) << __func__; |
| power_manager::SuspendImminent proto; |
| if (!DeserializeProtocolBuffer(serialized_proto, &proto)) { |
| LOG(ERROR) << "Failed to parse SuspendImminent signal."; |
| return; |
| } |
| delegate_->OnSuspendImminent(proto.suspend_id()); |
| } |
| |
| void ChromeosPowerManagerProxy::SuspendDone( |
| const vector<uint8_t>& serialized_proto) { |
| LOG(INFO) << __func__; |
| power_manager::SuspendDone proto; |
| if (!DeserializeProtocolBuffer(serialized_proto, &proto)) { |
| LOG(ERROR) << "Failed to parse SuspendDone signal."; |
| return; |
| } |
| delegate_->OnSuspendDone(proto.suspend_id()); |
| } |
| |
| void ChromeosPowerManagerProxy::DarkSuspendImminent( |
| const vector<uint8_t>& serialized_proto) { |
| LOG(INFO) << __func__; |
| power_manager::SuspendImminent proto; |
| if (!DeserializeProtocolBuffer(serialized_proto, &proto)) { |
| LOG(ERROR) << "Failed to parse DarkSuspendImminent signal."; |
| return; |
| } |
| delegate_->OnDarkSuspendImminent(proto.suspend_id()); |
| } |
| |
| void ChromeosPowerManagerProxy::OnServiceAvailable(bool available) { |
| // The only time this function will ever be invoked with |available| set to |
| // false is when we failed to connect the signals, either bus is not setup |
| // yet or we failed to add match rules, and both of these errors are |
| // considered fatal. |
| CHECK(available); |
| |
| // Service is available now, continuously monitor the service owner changes. |
| proxy_->GetObjectProxy()->SetNameOwnerChangedCallback( |
| base::Bind(&ChromeosPowerManagerProxy::OnServiceOwnerChanged, |
| weak_factory_.GetWeakPtr())); |
| |
| // The callback might invoke calls to the ObjectProxy, so defer the callback |
| // to event loop. |
| if (!service_appeared_callback_.is_null()) { |
| dispatcher_->PostTask(service_appeared_callback_); |
| } |
| |
| service_available_ = true; |
| } |
| |
| void ChromeosPowerManagerProxy::OnServiceOwnerChanged( |
| const string& old_owner, const string& new_owner) { |
| LOG(INFO) << __func__ << "old: " << old_owner << " new: " << new_owner; |
| |
| if (new_owner.empty()) { |
| // The callback might invoke calls to the ObjectProxy, so defer the |
| // callback to event loop. |
| if (!service_vanished_callback_.is_null()) { |
| dispatcher_->PostTask(service_vanished_callback_); |
| } |
| service_available_ = false; |
| } else { |
| // The callback might invoke calls to the ObjectProxy, so defer the |
| // callback to event loop. |
| if (!service_appeared_callback_.is_null()) { |
| dispatcher_->PostTask(service_appeared_callback_); |
| } |
| service_available_ = true; |
| } |
| } |
| |
| void ChromeosPowerManagerProxy::OnSignalConnected( |
| const string& interface_name, const string& signal_name, bool success) { |
| LOG(INFO) << __func__ << " interface: " << interface_name |
| << " signal: " << signal_name << "success: " << success; |
| if (!success) { |
| LOG(ERROR) << "Failed to connect signal " << signal_name |
| << " to interface " << interface_name; |
| } |
| } |
| |
| } // namespace shill |