1 //
2 // Copyright (C) 2014 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 "trunks/trunks_dbus_proxy.h"
18
19 #include <base/bind.h>
20 #include <brillo/bind_lambda.h>
21 #include <brillo/dbus/dbus_method_invoker.h>
22
23 #include "trunks/dbus_interface.h"
24 #include "trunks/error_codes.h"
25 #include "trunks/interface.pb.h"
26
27 namespace {
28
29 // Use a five minute timeout because some commands on some TPM hardware can take
30 // a very long time. If a few lengthy operations are already in the queue, a
31 // subsequent command needs to wait for all of them. Timeouts are always
32 // possible but under normal conditions 5 minutes seems to be plenty.
33 const int kDBusMaxTimeout = 5 * 60 * 1000;
34
35 } // namespace
36
37 namespace trunks {
38
TrunksDBusProxy()39 TrunksDBusProxy::TrunksDBusProxy() : weak_factory_(this) {}
40
~TrunksDBusProxy()41 TrunksDBusProxy::~TrunksDBusProxy() {
42 if (bus_) {
43 bus_->ShutdownAndBlock();
44 }
45 }
46
Init()47 bool TrunksDBusProxy::Init() {
48 dbus::Bus::Options options;
49 options.bus_type = dbus::Bus::SYSTEM;
50 bus_ = new dbus::Bus(options);
51 object_proxy_ = bus_->GetObjectProxy(
52 trunks::kTrunksServiceName, dbus::ObjectPath(trunks::kTrunksServicePath));
53 origin_thread_id_ = base::PlatformThread::CurrentId();
54 return (object_proxy_ != nullptr);
55 }
56
SendCommand(const std::string & command,const ResponseCallback & callback)57 void TrunksDBusProxy::SendCommand(const std::string& command,
58 const ResponseCallback& callback) {
59 if (origin_thread_id_ != base::PlatformThread::CurrentId()) {
60 LOG(ERROR) << "Error TrunksDBusProxy cannot be shared by multiple threads.";
61 callback.Run(CreateErrorResponse(TRUNKS_RC_IPC_ERROR));
62 }
63 SendCommandRequest tpm_command_proto;
64 tpm_command_proto.set_command(command);
65 auto on_success = [callback](const SendCommandResponse& response) {
66 callback.Run(response.response());
67 };
68 auto on_error = [callback](brillo::Error* error) {
69 SendCommandResponse response;
70 response.set_response(CreateErrorResponse(SAPI_RC_NO_RESPONSE_RECEIVED));
71 callback.Run(response.response());
72 };
73 brillo::dbus_utils::CallMethodWithTimeout(
74 kDBusMaxTimeout, object_proxy_, trunks::kTrunksInterface,
75 trunks::kSendCommand, base::Bind(on_success), base::Bind(on_error),
76 tpm_command_proto);
77 }
78
SendCommandAndWait(const std::string & command)79 std::string TrunksDBusProxy::SendCommandAndWait(const std::string& command) {
80 if (origin_thread_id_ != base::PlatformThread::CurrentId()) {
81 LOG(ERROR) << "Error TrunksDBusProxy cannot be shared by multiple threads.";
82 return CreateErrorResponse(TRUNKS_RC_IPC_ERROR);
83 }
84 SendCommandRequest tpm_command_proto;
85 tpm_command_proto.set_command(command);
86 brillo::ErrorPtr error;
87 std::unique_ptr<dbus::Response> dbus_response =
88 brillo::dbus_utils::CallMethodAndBlockWithTimeout(
89 kDBusMaxTimeout, object_proxy_, trunks::kTrunksInterface,
90 trunks::kSendCommand, &error, tpm_command_proto);
91 SendCommandResponse tpm_response_proto;
92 if (dbus_response.get() &&
93 brillo::dbus_utils::ExtractMethodCallResults(dbus_response.get(), &error,
94 &tpm_response_proto)) {
95 return tpm_response_proto.response();
96 } else {
97 LOG(ERROR) << "TrunksProxy could not parse response: "
98 << error->GetMessage();
99 return CreateErrorResponse(SAPI_RC_MALFORMED_RESPONSE);
100 }
101 }
102
103 } // namespace trunks
104