blob: a1fbbf321c8afc680081696bed62a842f7daba4f [file] [log] [blame]
Yifan Hong8c950422021-08-05 17:13:55 -07001/*
2 * Copyright (C) 2021 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#define LOG_TAG "FdTrigger"
18#include <log/log.h>
19
Yifan Honge0b37bd2021-09-23 17:23:02 -070020#include "FdTrigger.h"
21
Yifan Hong8c950422021-08-05 17:13:55 -070022#include <poll.h>
23
Tomasz Wasilczyk1de48a22023-10-30 14:19:19 +000024#include <binder/Functional.h>
Yifan Hong8c950422021-08-05 17:13:55 -070025
Yifan Honge0b37bd2021-09-23 17:23:02 -070026#include "RpcState.h"
Tomasz Wasilczykdf07f942023-11-02 15:07:45 -070027#include "Utils.h"
28
Yifan Hong8c950422021-08-05 17:13:55 -070029namespace android {
30
Tomasz Wasilczyk1de48a22023-10-30 14:19:19 +000031using namespace android::binder::impl;
32
Yifan Hong8c950422021-08-05 17:13:55 -070033std::unique_ptr<FdTrigger> FdTrigger::make() {
34 auto ret = std::make_unique<FdTrigger>();
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000035#ifndef BINDER_RPC_SINGLE_THREADED
Yifan Hong8c950422021-08-05 17:13:55 -070036 if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
37 ALOGE("Could not create pipe %s", strerror(errno));
38 return nullptr;
39 }
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000040#endif
Yifan Hong8c950422021-08-05 17:13:55 -070041 return ret;
42}
43
44void FdTrigger::trigger() {
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000045#ifdef BINDER_RPC_SINGLE_THREADED
46 mTriggered = true;
47#else
Yifan Hong8c950422021-08-05 17:13:55 -070048 mWrite.reset();
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000049#endif
Yifan Hong8c950422021-08-05 17:13:55 -070050}
51
52bool FdTrigger::isTriggered() {
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000053#ifdef BINDER_RPC_SINGLE_THREADED
54 return mTriggered;
55#else
Yifan Hong8c950422021-08-05 17:13:55 -070056 return mWrite == -1;
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000057#endif
Yifan Hong8c950422021-08-05 17:13:55 -070058}
59
Pawan3e0061c2022-08-26 21:08:34 +000060status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, int16_t event) {
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000061#ifdef BINDER_RPC_SINGLE_THREADED
62 if (mTriggered) {
63 return DEAD_OBJECT;
64 }
65#endif
66
Pawan49d74cb2022-08-03 21:19:11 +000067 LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed",
68 transportFd.fd.get());
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000069 pollfd pfd[]{
Pawan49d74cb2022-08-03 21:19:11 +000070 {.fd = transportFd.fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000071#ifndef BINDER_RPC_SINGLE_THREADED
72 {.fd = mRead.get(), .events = 0, .revents = 0},
73#endif
74 };
Pawan49d74cb2022-08-03 21:19:11 +000075
76 LOG_ALWAYS_FATAL_IF(transportFd.isInPollingState() == true,
77 "Only one thread should be polling on Fd!");
78
79 transportFd.setPollingState(true);
Tomasz Wasilczyk1de48a22023-10-30 14:19:19 +000080 auto pollingStateGuard = make_scope_guard([&]() { transportFd.setPollingState(false); });
Pawan49d74cb2022-08-03 21:19:11 +000081
Tomasz Wasilczykdf07f942023-11-02 15:07:45 -070082 int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1));
Yifan Honge0b37bd2021-09-23 17:23:02 -070083 if (ret < 0) {
84 return -errno;
Yifan Hong8c950422021-08-05 17:13:55 -070085 }
Pawan49d74cb2022-08-03 21:19:11 +000086 LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
Yifan Honge0b37bd2021-09-23 17:23:02 -070087
88 // At least one FD has events. Check them.
89
Andrei Homescuffa3aaa2022-04-07 05:06:33 +000090#ifndef BINDER_RPC_SINGLE_THREADED
Yifan Honge0b37bd2021-09-23 17:23:02 -070091 // Detect explicit trigger(): DEAD_OBJECT
92 if (pfd[1].revents & POLLHUP) {
93 return DEAD_OBJECT;
94 }
95 // See unknown flags in trigger FD's revents (POLLERR / POLLNVAL).
96 // Treat this error condition as UNKNOWN_ERROR.
97 if (pfd[1].revents != 0) {
98 ALOGE("Unknown revents on trigger FD %d: revents = %d", pfd[1].fd, pfd[1].revents);
99 return UNKNOWN_ERROR;
100 }
101
102 // pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
103 // a subset of event | POLLHUP | POLLERR | POLLNVAL.
Andrei Homescuffa3aaa2022-04-07 05:06:33 +0000104#endif
Yifan Honge0b37bd2021-09-23 17:23:02 -0700105
106 // POLLNVAL: invalid FD number, e.g. not opened.
107 if (pfd[0].revents & POLLNVAL) {
108 return BAD_VALUE;
109 }
110
111 // Error condition. It wouldn't be possible to do I/O on |fd| afterwards.
112 // Note: If this is the write end of a pipe then POLLHUP may also be set simultaneously. We
113 // still want DEAD_OBJECT in this case.
114 if (pfd[0].revents & POLLERR) {
115 LOG_RPC_DETAIL("poll() incoming FD %d results in revents = %d", pfd[0].fd, pfd[0].revents);
116 return DEAD_OBJECT;
117 }
118
119 // Success condition; event flag(s) set. Even though POLLHUP may also be set,
120 // treat it as a success condition to ensure data is drained.
121 if (pfd[0].revents & event) {
122 return OK;
123 }
124
125 // POLLHUP: Peer closed connection. Treat as DEAD_OBJECT.
126 // This is a very common case, so don't log.
127 return DEAD_OBJECT;
Yifan Hong8c950422021-08-05 17:13:55 -0700128}
129
Yifan Hong8c950422021-08-05 17:13:55 -0700130} // namespace android