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 <brillo/binder_watcher.h>
18
19#include <base/bind.h>
20#include <base/logging.h>
21#include <binder/IPCThreadState.h>
22#include <binder/ProcessState.h>
23
24using android::IPCThreadState;
25using android::ProcessState;
26
27namespace {
28// Called from the message loop whenever the binder file descriptor is ready.
29void OnBinderReadReady() {
30  IPCThreadState::self()->handlePolledCommands();
31}
32}  // namespace
33
34namespace brillo {
35
36BinderWatcher::BinderWatcher(MessageLoop* message_loop)
37    : message_loop_(message_loop) {}
38
39BinderWatcher::BinderWatcher() : message_loop_(nullptr) {}
40
41BinderWatcher::~BinderWatcher() {
42  if (task_id_ != MessageLoop::kTaskIdNull)
43    message_loop_->CancelTask(task_id_);
44}
45
46bool BinderWatcher::Init() {
47  if (!message_loop_)
48    message_loop_ = MessageLoop::current();
49  if (!message_loop_) {
50    LOG(ERROR) << "Must initialize a brillo::MessageLoop to use BinderWatcher";
51    return false;
52  }
53
54  int binder_fd = -1;
55  ProcessState::self()->setThreadPoolMaxThreadCount(0);
56  IPCThreadState::self()->disableBackgroundScheduling(true);
57  int err = IPCThreadState::self()->setupPolling(&binder_fd);
58  if (err != 0) {
59    LOG(ERROR) << "Error setting up binder polling: "
60               << logging::SystemErrorCodeToString(err);
61    return false;
62  }
63  if (binder_fd < 0) {
64    LOG(ERROR) << "Invalid binder FD " << binder_fd;
65    return false;
66  }
67  VLOG(1) << "Got binder FD " << binder_fd;
68
69  task_id_ = message_loop_->WatchFileDescriptor(
70      FROM_HERE,
71      binder_fd,
72      MessageLoop::kWatchRead,
73      true /* persistent */,
74      base::Bind(&OnBinderReadReady));
75  if (task_id_ == MessageLoop::kTaskIdNull) {
76    LOG(ERROR) << "Failed to watch binder FD";
77    return false;
78  }
79  return true;
80}
81
82}  // namespace brillo
83