1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "FdTrigger"
18*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker #include "FdTrigger.h"
21*38e8c45fSAndroid Build Coastguard Worker
22*38e8c45fSAndroid Build Coastguard Worker #include <poll.h>
23*38e8c45fSAndroid Build Coastguard Worker
24*38e8c45fSAndroid Build Coastguard Worker #include <binder/Functional.h>
25*38e8c45fSAndroid Build Coastguard Worker
26*38e8c45fSAndroid Build Coastguard Worker #include "FdUtils.h"
27*38e8c45fSAndroid Build Coastguard Worker #include "RpcState.h"
28*38e8c45fSAndroid Build Coastguard Worker #include "Utils.h"
29*38e8c45fSAndroid Build Coastguard Worker
30*38e8c45fSAndroid Build Coastguard Worker namespace android {
31*38e8c45fSAndroid Build Coastguard Worker
32*38e8c45fSAndroid Build Coastguard Worker using namespace android::binder::impl;
33*38e8c45fSAndroid Build Coastguard Worker
make()34*38e8c45fSAndroid Build Coastguard Worker std::unique_ptr<FdTrigger> FdTrigger::make() {
35*38e8c45fSAndroid Build Coastguard Worker auto ret = std::make_unique<FdTrigger>();
36*38e8c45fSAndroid Build Coastguard Worker #ifndef BINDER_RPC_SINGLE_THREADED
37*38e8c45fSAndroid Build Coastguard Worker if (!binder::Pipe(&ret->mRead, &ret->mWrite)) {
38*38e8c45fSAndroid Build Coastguard Worker ALOGE("Could not create pipe %s", strerror(errno));
39*38e8c45fSAndroid Build Coastguard Worker return nullptr;
40*38e8c45fSAndroid Build Coastguard Worker }
41*38e8c45fSAndroid Build Coastguard Worker #endif
42*38e8c45fSAndroid Build Coastguard Worker return ret;
43*38e8c45fSAndroid Build Coastguard Worker }
44*38e8c45fSAndroid Build Coastguard Worker
trigger()45*38e8c45fSAndroid Build Coastguard Worker void FdTrigger::trigger() {
46*38e8c45fSAndroid Build Coastguard Worker #ifdef BINDER_RPC_SINGLE_THREADED
47*38e8c45fSAndroid Build Coastguard Worker mTriggered = true;
48*38e8c45fSAndroid Build Coastguard Worker #else
49*38e8c45fSAndroid Build Coastguard Worker mWrite.reset();
50*38e8c45fSAndroid Build Coastguard Worker #endif
51*38e8c45fSAndroid Build Coastguard Worker }
52*38e8c45fSAndroid Build Coastguard Worker
isTriggered()53*38e8c45fSAndroid Build Coastguard Worker bool FdTrigger::isTriggered() {
54*38e8c45fSAndroid Build Coastguard Worker #ifdef BINDER_RPC_SINGLE_THREADED
55*38e8c45fSAndroid Build Coastguard Worker return mTriggered;
56*38e8c45fSAndroid Build Coastguard Worker #else
57*38e8c45fSAndroid Build Coastguard Worker return !mWrite.ok();
58*38e8c45fSAndroid Build Coastguard Worker #endif
59*38e8c45fSAndroid Build Coastguard Worker }
60*38e8c45fSAndroid Build Coastguard Worker
triggerablePoll(const android::RpcTransportFd & transportFd,int16_t event)61*38e8c45fSAndroid Build Coastguard Worker status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, int16_t event) {
62*38e8c45fSAndroid Build Coastguard Worker #ifdef BINDER_RPC_SINGLE_THREADED
63*38e8c45fSAndroid Build Coastguard Worker if (mTriggered) {
64*38e8c45fSAndroid Build Coastguard Worker return DEAD_OBJECT;
65*38e8c45fSAndroid Build Coastguard Worker }
66*38e8c45fSAndroid Build Coastguard Worker #endif
67*38e8c45fSAndroid Build Coastguard Worker
68*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed",
69*38e8c45fSAndroid Build Coastguard Worker transportFd.fd.get());
70*38e8c45fSAndroid Build Coastguard Worker pollfd pfd[]{
71*38e8c45fSAndroid Build Coastguard Worker {.fd = transportFd.fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
72*38e8c45fSAndroid Build Coastguard Worker #ifndef BINDER_RPC_SINGLE_THREADED
73*38e8c45fSAndroid Build Coastguard Worker {.fd = mRead.get(), .events = 0, .revents = 0},
74*38e8c45fSAndroid Build Coastguard Worker #endif
75*38e8c45fSAndroid Build Coastguard Worker };
76*38e8c45fSAndroid Build Coastguard Worker
77*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(transportFd.isInPollingState() == true,
78*38e8c45fSAndroid Build Coastguard Worker "Only one thread should be polling on Fd!");
79*38e8c45fSAndroid Build Coastguard Worker
80*38e8c45fSAndroid Build Coastguard Worker transportFd.setPollingState(true);
81*38e8c45fSAndroid Build Coastguard Worker auto pollingStateGuard = make_scope_guard([&]() { transportFd.setPollingState(false); });
82*38e8c45fSAndroid Build Coastguard Worker
83*38e8c45fSAndroid Build Coastguard Worker int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1));
84*38e8c45fSAndroid Build Coastguard Worker if (ret < 0) {
85*38e8c45fSAndroid Build Coastguard Worker int saved_errno = errno;
86*38e8c45fSAndroid Build Coastguard Worker ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno));
87*38e8c45fSAndroid Build Coastguard Worker return -saved_errno;
88*38e8c45fSAndroid Build Coastguard Worker }
89*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get());
90*38e8c45fSAndroid Build Coastguard Worker
91*38e8c45fSAndroid Build Coastguard Worker // At least one FD has events. Check them.
92*38e8c45fSAndroid Build Coastguard Worker
93*38e8c45fSAndroid Build Coastguard Worker #ifndef BINDER_RPC_SINGLE_THREADED
94*38e8c45fSAndroid Build Coastguard Worker // Detect explicit trigger(): DEAD_OBJECT
95*38e8c45fSAndroid Build Coastguard Worker if (pfd[1].revents & POLLHUP) {
96*38e8c45fSAndroid Build Coastguard Worker return DEAD_OBJECT;
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker // See unknown flags in trigger FD's revents (POLLERR / POLLNVAL).
99*38e8c45fSAndroid Build Coastguard Worker // Treat this error condition as UNKNOWN_ERROR.
100*38e8c45fSAndroid Build Coastguard Worker if (pfd[1].revents != 0) {
101*38e8c45fSAndroid Build Coastguard Worker ALOGE("Unknown revents on trigger FD %d: revents = %d", pfd[1].fd, pfd[1].revents);
102*38e8c45fSAndroid Build Coastguard Worker return UNKNOWN_ERROR;
103*38e8c45fSAndroid Build Coastguard Worker }
104*38e8c45fSAndroid Build Coastguard Worker
105*38e8c45fSAndroid Build Coastguard Worker // pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
106*38e8c45fSAndroid Build Coastguard Worker // a subset of event | POLLHUP | POLLERR | POLLNVAL.
107*38e8c45fSAndroid Build Coastguard Worker #endif
108*38e8c45fSAndroid Build Coastguard Worker
109*38e8c45fSAndroid Build Coastguard Worker // POLLNVAL: invalid FD number, e.g. not opened.
110*38e8c45fSAndroid Build Coastguard Worker if (pfd[0].revents & POLLNVAL) {
111*38e8c45fSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd);
112*38e8c45fSAndroid Build Coastguard Worker return BAD_VALUE;
113*38e8c45fSAndroid Build Coastguard Worker }
114*38e8c45fSAndroid Build Coastguard Worker
115*38e8c45fSAndroid Build Coastguard Worker // Error condition. It wouldn't be possible to do I/O on |fd| afterwards.
116*38e8c45fSAndroid Build Coastguard Worker // Note: If this is the write end of a pipe then POLLHUP may also be set simultaneously. We
117*38e8c45fSAndroid Build Coastguard Worker // still want DEAD_OBJECT in this case.
118*38e8c45fSAndroid Build Coastguard Worker if (pfd[0].revents & POLLERR) {
119*38e8c45fSAndroid Build Coastguard Worker LOG_RPC_DETAIL("poll() incoming FD %d results in revents = %d", pfd[0].fd, pfd[0].revents);
120*38e8c45fSAndroid Build Coastguard Worker return DEAD_OBJECT;
121*38e8c45fSAndroid Build Coastguard Worker }
122*38e8c45fSAndroid Build Coastguard Worker
123*38e8c45fSAndroid Build Coastguard Worker // Success condition; event flag(s) set. Even though POLLHUP may also be set,
124*38e8c45fSAndroid Build Coastguard Worker // treat it as a success condition to ensure data is drained.
125*38e8c45fSAndroid Build Coastguard Worker if (pfd[0].revents & event) {
126*38e8c45fSAndroid Build Coastguard Worker return OK;
127*38e8c45fSAndroid Build Coastguard Worker }
128*38e8c45fSAndroid Build Coastguard Worker
129*38e8c45fSAndroid Build Coastguard Worker // POLLHUP: Peer closed connection. Treat as DEAD_OBJECT.
130*38e8c45fSAndroid Build Coastguard Worker // This is a very common case, so don't log.
131*38e8c45fSAndroid Build Coastguard Worker return DEAD_OBJECT;
132*38e8c45fSAndroid Build Coastguard Worker }
133*38e8c45fSAndroid Build Coastguard Worker
134*38e8c45fSAndroid Build Coastguard Worker } // namespace android
135