xref: /aosp_15_r20/frameworks/native/libs/binder/FdTrigger.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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