1//
2// Copyright (C) 2016 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_binder_service.h"
18
19#include <sysexits.h>
20
21#include <base/bind.h>
22#include <binderwrapper/binder_wrapper.h>
23
24#include "trunks/binder_interface.h"
25#include "trunks/command_transceiver.h"
26#include "trunks/error_codes.h"
27#include "trunks/interface.pb.h"
28
29namespace {
30
31// If |command| is a valid command protobuf, provides the |command_data| and
32// returns true. Otherwise, returns false.
33bool ParseCommandProto(const std::vector<uint8_t>& command,
34                       std::string* command_data) {
35  trunks::SendCommandRequest request_proto;
36  if (!request_proto.ParseFromArray(command.data(), command.size()) ||
37      !request_proto.has_command() || request_proto.command().empty()) {
38    return false;
39  }
40  *command_data = request_proto.command();
41  return true;
42}
43
44void CreateResponseProto(const std::string& data,
45                         std::vector<uint8_t>* response) {
46  trunks::SendCommandResponse response_proto;
47  response_proto.set_response(data);
48  response->resize(response_proto.ByteSize());
49  CHECK(response_proto.SerializeToArray(response->data(), response->size()))
50      << "TrunksBinderService: Failed to serialize protobuf.";
51}
52
53}  // namespace
54
55namespace trunks {
56
57int TrunksBinderService::OnInit() {
58  android::BinderWrapper::Create();
59  if (!watcher_.Init()) {
60    LOG(ERROR) << "TrunksBinderService: BinderWatcher::Init failed.";
61    return EX_UNAVAILABLE;
62  }
63  binder_ = new BinderServiceInternal(this);
64  if (!android::BinderWrapper::Get()->RegisterService(
65          kTrunksServiceName, android::IInterface::asBinder(binder_))) {
66    LOG(ERROR) << "TrunksBinderService: RegisterService failed.";
67    return EX_UNAVAILABLE;
68  }
69  LOG(INFO) << "Trunks: Binder service registered.";
70  return brillo::Daemon::OnInit();
71}
72
73TrunksBinderService::BinderServiceInternal::BinderServiceInternal(
74    TrunksBinderService* service)
75    : service_(service) {}
76
77android::binder::Status TrunksBinderService::BinderServiceInternal::SendCommand(
78    const std::vector<uint8_t>& command,
79    const android::sp<android::trunks::ITrunksClient>& client) {
80  auto callback =
81      base::Bind(&TrunksBinderService::BinderServiceInternal::OnResponse,
82                 GetWeakPtr(), client);
83  std::string command_data;
84  if (!ParseCommandProto(command, &command_data)) {
85    LOG(ERROR) << "TrunksBinderService: Bad command data.";
86    callback.Run(CreateErrorResponse(SAPI_RC_BAD_PARAMETER));
87    return android::binder::Status::ok();
88  }
89  service_->transceiver_->SendCommand(command_data, callback);
90  return android::binder::Status::ok();
91}
92
93void TrunksBinderService::BinderServiceInternal::OnResponse(
94    const android::sp<android::trunks::ITrunksClient>& client,
95    const std::string& response) {
96  std::vector<uint8_t> binder_response;
97  CreateResponseProto(response, &binder_response);
98  android::binder::Status status = client->OnCommandResponse(binder_response);
99  if (!status.isOk()) {
100    LOG(ERROR) << "TrunksBinderService: Failed to send response to client: "
101               << status.toString8();
102  }
103}
104
105android::binder::Status
106TrunksBinderService::BinderServiceInternal::SendCommandAndWait(
107    const std::vector<uint8_t>& command,
108    std::vector<uint8_t>* response) {
109  std::string command_data;
110  if (!ParseCommandProto(command, &command_data)) {
111    LOG(ERROR) << "TrunksBinderService: Bad command data.";
112    CreateResponseProto(CreateErrorResponse(SAPI_RC_BAD_PARAMETER), response);
113    return android::binder::Status::ok();
114  }
115  CreateResponseProto(service_->transceiver_->SendCommandAndWait(command_data),
116                      response);
117  return android::binder::Status::ok();
118}
119
120}  // namespace trunks
121