• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
20 #include "FdTrigger.h"
21 
22 #include <poll.h>
23 
24 #include <android-base/macros.h>
25 
26 #include "RpcState.h"
27 namespace android {
28 
make()29 std::unique_ptr<FdTrigger> FdTrigger::make() {
30     auto ret = std::make_unique<FdTrigger>();
31     if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
32         ALOGE("Could not create pipe %s", strerror(errno));
33         return nullptr;
34     }
35     return ret;
36 }
37 
trigger()38 void FdTrigger::trigger() {
39     mWrite.reset();
40 }
41 
isTriggered()42 bool FdTrigger::isTriggered() {
43     return mWrite == -1;
44 }
45 
triggerablePoll(base::borrowed_fd fd,int16_t event)46 status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
47     LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed", fd.get());
48     pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
49                  {.fd = mRead.get(), .events = 0, .revents = 0}};
50     int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
51     if (ret < 0) {
52         return -errno;
53     }
54     LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", fd.get());
55 
56     // At least one FD has events. Check them.
57 
58     // Detect explicit trigger(): DEAD_OBJECT
59     if (pfd[1].revents & POLLHUP) {
60         return DEAD_OBJECT;
61     }
62     // See unknown flags in trigger FD's revents (POLLERR / POLLNVAL).
63     // Treat this error condition as UNKNOWN_ERROR.
64     if (pfd[1].revents != 0) {
65         ALOGE("Unknown revents on trigger FD %d: revents = %d", pfd[1].fd, pfd[1].revents);
66         return UNKNOWN_ERROR;
67     }
68 
69     // pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
70     // a subset of event | POLLHUP | POLLERR | POLLNVAL.
71 
72     // POLLNVAL: invalid FD number, e.g. not opened.
73     if (pfd[0].revents & POLLNVAL) {
74         return BAD_VALUE;
75     }
76 
77     // Error condition. It wouldn't be possible to do I/O on |fd| afterwards.
78     // Note: If this is the write end of a pipe then POLLHUP may also be set simultaneously. We
79     //   still want DEAD_OBJECT in this case.
80     if (pfd[0].revents & POLLERR) {
81         LOG_RPC_DETAIL("poll() incoming FD %d results in revents = %d", pfd[0].fd, pfd[0].revents);
82         return DEAD_OBJECT;
83     }
84 
85     // Success condition; event flag(s) set. Even though POLLHUP may also be set,
86     // treat it as a success condition to ensure data is drained.
87     if (pfd[0].revents & event) {
88         return OK;
89     }
90 
91     // POLLHUP: Peer closed connection. Treat as DEAD_OBJECT.
92     // This is a very common case, so don't log.
93     return DEAD_OBJECT;
94 }
95 
96 } // namespace android
97