xref: /aosp_15_r20/system/core/libappfuse/FuseBridgeLoop.cc (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  *
4*00c7fec1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker  *
8*00c7fec1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker  *
10*00c7fec1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker  * See the License for the specic language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker  * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker  */
16*00c7fec1SAndroid Build Coastguard Worker 
17*00c7fec1SAndroid Build Coastguard Worker #include "libappfuse/FuseBridgeLoop.h"
18*00c7fec1SAndroid Build Coastguard Worker 
19*00c7fec1SAndroid Build Coastguard Worker #include <sys/epoll.h>
20*00c7fec1SAndroid Build Coastguard Worker #include <sys/socket.h>
21*00c7fec1SAndroid Build Coastguard Worker 
22*00c7fec1SAndroid Build Coastguard Worker #include <unordered_map>
23*00c7fec1SAndroid Build Coastguard Worker 
24*00c7fec1SAndroid Build Coastguard Worker #include <android-base/logging.h>
25*00c7fec1SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
26*00c7fec1SAndroid Build Coastguard Worker 
27*00c7fec1SAndroid Build Coastguard Worker #include "libappfuse/EpollController.h"
28*00c7fec1SAndroid Build Coastguard Worker 
29*00c7fec1SAndroid Build Coastguard Worker namespace android {
30*00c7fec1SAndroid Build Coastguard Worker namespace fuse {
31*00c7fec1SAndroid Build Coastguard Worker namespace {
32*00c7fec1SAndroid Build Coastguard Worker 
33*00c7fec1SAndroid Build Coastguard Worker enum class FuseBridgeState { kWaitToReadEither, kWaitToReadProxy, kWaitToWriteProxy, kClosing };
34*00c7fec1SAndroid Build Coastguard Worker 
35*00c7fec1SAndroid Build Coastguard Worker struct FuseBridgeEntryEvent {
36*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeEntry* entry;
37*00c7fec1SAndroid Build Coastguard Worker     int events;
38*00c7fec1SAndroid Build Coastguard Worker };
39*00c7fec1SAndroid Build Coastguard Worker 
GetObservedEvents(FuseBridgeState state,int * device_events,int * proxy_events)40*00c7fec1SAndroid Build Coastguard Worker void GetObservedEvents(FuseBridgeState state, int* device_events, int* proxy_events) {
41*00c7fec1SAndroid Build Coastguard Worker     switch (state) {
42*00c7fec1SAndroid Build Coastguard Worker         case FuseBridgeState::kWaitToReadEither:
43*00c7fec1SAndroid Build Coastguard Worker             *device_events = EPOLLIN;
44*00c7fec1SAndroid Build Coastguard Worker             *proxy_events = EPOLLIN;
45*00c7fec1SAndroid Build Coastguard Worker             return;
46*00c7fec1SAndroid Build Coastguard Worker         case FuseBridgeState::kWaitToReadProxy:
47*00c7fec1SAndroid Build Coastguard Worker             *device_events = 0;
48*00c7fec1SAndroid Build Coastguard Worker             *proxy_events = EPOLLIN;
49*00c7fec1SAndroid Build Coastguard Worker             return;
50*00c7fec1SAndroid Build Coastguard Worker         case FuseBridgeState::kWaitToWriteProxy:
51*00c7fec1SAndroid Build Coastguard Worker             *device_events = 0;
52*00c7fec1SAndroid Build Coastguard Worker             *proxy_events = EPOLLOUT;
53*00c7fec1SAndroid Build Coastguard Worker             return;
54*00c7fec1SAndroid Build Coastguard Worker         case FuseBridgeState::kClosing:
55*00c7fec1SAndroid Build Coastguard Worker             *device_events = 0;
56*00c7fec1SAndroid Build Coastguard Worker             *proxy_events = 0;
57*00c7fec1SAndroid Build Coastguard Worker             return;
58*00c7fec1SAndroid Build Coastguard Worker     }
59*00c7fec1SAndroid Build Coastguard Worker }
60*00c7fec1SAndroid Build Coastguard Worker 
LogResponseError(const std::string & message,const FuseResponse & response)61*00c7fec1SAndroid Build Coastguard Worker void LogResponseError(const std::string& message, const FuseResponse& response) {
62*00c7fec1SAndroid Build Coastguard Worker     LOG(ERROR) << message << ": header.len=" << response.header.len
63*00c7fec1SAndroid Build Coastguard Worker                << " header.error=" << response.header.error
64*00c7fec1SAndroid Build Coastguard Worker                << " header.unique=" << response.header.unique;
65*00c7fec1SAndroid Build Coastguard Worker }
66*00c7fec1SAndroid Build Coastguard Worker }
67*00c7fec1SAndroid Build Coastguard Worker 
68*00c7fec1SAndroid Build Coastguard Worker class FuseBridgeEntry {
69*00c7fec1SAndroid Build Coastguard Worker   public:
FuseBridgeEntry(int mount_id,base::unique_fd && dev_fd,base::unique_fd && proxy_fd)70*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeEntry(int mount_id, base::unique_fd&& dev_fd, base::unique_fd&& proxy_fd)
71*00c7fec1SAndroid Build Coastguard Worker         : mount_id_(mount_id),
72*00c7fec1SAndroid Build Coastguard Worker           device_fd_(std::move(dev_fd)),
73*00c7fec1SAndroid Build Coastguard Worker           proxy_fd_(std::move(proxy_fd)),
74*00c7fec1SAndroid Build Coastguard Worker           state_(FuseBridgeState::kWaitToReadEither),
75*00c7fec1SAndroid Build Coastguard Worker           last_state_(FuseBridgeState::kWaitToReadEither),
76*00c7fec1SAndroid Build Coastguard Worker           last_device_events_({this, 0}),
77*00c7fec1SAndroid Build Coastguard Worker           last_proxy_events_({this, 0}),
78*00c7fec1SAndroid Build Coastguard Worker           open_count_(0) {}
79*00c7fec1SAndroid Build Coastguard Worker 
80*00c7fec1SAndroid Build Coastguard Worker     // Transfer bytes depends on availability of FDs and the internal |state_|.
Transfer(FuseBridgeLoopCallback * callback)81*00c7fec1SAndroid Build Coastguard Worker     void Transfer(FuseBridgeLoopCallback* callback) {
82*00c7fec1SAndroid Build Coastguard Worker         constexpr int kUnexpectedEventMask = ~(EPOLLIN | EPOLLOUT);
83*00c7fec1SAndroid Build Coastguard Worker         const bool unexpected_event = (last_device_events_.events & kUnexpectedEventMask) ||
84*00c7fec1SAndroid Build Coastguard Worker                                       (last_proxy_events_.events & kUnexpectedEventMask);
85*00c7fec1SAndroid Build Coastguard Worker         const bool device_read_ready = last_device_events_.events & EPOLLIN;
86*00c7fec1SAndroid Build Coastguard Worker         const bool proxy_read_ready = last_proxy_events_.events & EPOLLIN;
87*00c7fec1SAndroid Build Coastguard Worker         const bool proxy_write_ready = last_proxy_events_.events & EPOLLOUT;
88*00c7fec1SAndroid Build Coastguard Worker 
89*00c7fec1SAndroid Build Coastguard Worker         last_state_ = state_;
90*00c7fec1SAndroid Build Coastguard Worker         last_device_events_.events = 0;
91*00c7fec1SAndroid Build Coastguard Worker         last_proxy_events_.events = 0;
92*00c7fec1SAndroid Build Coastguard Worker 
93*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "Transfer device_read_ready=" << device_read_ready
94*00c7fec1SAndroid Build Coastguard Worker                      << " proxy_read_ready=" << proxy_read_ready
95*00c7fec1SAndroid Build Coastguard Worker                      << " proxy_write_ready=" << proxy_write_ready;
96*00c7fec1SAndroid Build Coastguard Worker 
97*00c7fec1SAndroid Build Coastguard Worker         if (unexpected_event) {
98*00c7fec1SAndroid Build Coastguard Worker             LOG(ERROR) << "Invalid epoll event is observed";
99*00c7fec1SAndroid Build Coastguard Worker             state_ = FuseBridgeState::kClosing;
100*00c7fec1SAndroid Build Coastguard Worker             return;
101*00c7fec1SAndroid Build Coastguard Worker         }
102*00c7fec1SAndroid Build Coastguard Worker 
103*00c7fec1SAndroid Build Coastguard Worker         switch (state_) {
104*00c7fec1SAndroid Build Coastguard Worker             case FuseBridgeState::kWaitToReadEither:
105*00c7fec1SAndroid Build Coastguard Worker                 if (proxy_read_ready) {
106*00c7fec1SAndroid Build Coastguard Worker                     state_ = ReadFromProxy();
107*00c7fec1SAndroid Build Coastguard Worker                 } else if (device_read_ready) {
108*00c7fec1SAndroid Build Coastguard Worker                     state_ = ReadFromDevice(callback);
109*00c7fec1SAndroid Build Coastguard Worker                 }
110*00c7fec1SAndroid Build Coastguard Worker                 return;
111*00c7fec1SAndroid Build Coastguard Worker 
112*00c7fec1SAndroid Build Coastguard Worker             case FuseBridgeState::kWaitToReadProxy:
113*00c7fec1SAndroid Build Coastguard Worker                 CHECK(proxy_read_ready);
114*00c7fec1SAndroid Build Coastguard Worker                 state_ = ReadFromProxy();
115*00c7fec1SAndroid Build Coastguard Worker                 return;
116*00c7fec1SAndroid Build Coastguard Worker 
117*00c7fec1SAndroid Build Coastguard Worker             case FuseBridgeState::kWaitToWriteProxy:
118*00c7fec1SAndroid Build Coastguard Worker                 CHECK(proxy_write_ready);
119*00c7fec1SAndroid Build Coastguard Worker                 state_ = WriteToProxy();
120*00c7fec1SAndroid Build Coastguard Worker                 return;
121*00c7fec1SAndroid Build Coastguard Worker 
122*00c7fec1SAndroid Build Coastguard Worker             case FuseBridgeState::kClosing:
123*00c7fec1SAndroid Build Coastguard Worker                 return;
124*00c7fec1SAndroid Build Coastguard Worker         }
125*00c7fec1SAndroid Build Coastguard Worker     }
126*00c7fec1SAndroid Build Coastguard Worker 
IsClosing() const127*00c7fec1SAndroid Build Coastguard Worker     bool IsClosing() const { return state_ == FuseBridgeState::kClosing; }
128*00c7fec1SAndroid Build Coastguard Worker 
mount_id() const129*00c7fec1SAndroid Build Coastguard Worker     int mount_id() const { return mount_id_; }
130*00c7fec1SAndroid Build Coastguard Worker 
131*00c7fec1SAndroid Build Coastguard Worker   private:
132*00c7fec1SAndroid Build Coastguard Worker     friend class BridgeEpollController;
133*00c7fec1SAndroid Build Coastguard Worker 
ReadFromProxy()134*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeState ReadFromProxy() {
135*00c7fec1SAndroid Build Coastguard Worker         switch (buffer_.response.ReadOrAgain(proxy_fd_)) {
136*00c7fec1SAndroid Build Coastguard Worker             case ResultOrAgain::kSuccess:
137*00c7fec1SAndroid Build Coastguard Worker                 break;
138*00c7fec1SAndroid Build Coastguard Worker             case ResultOrAgain::kFailure:
139*00c7fec1SAndroid Build Coastguard Worker                 return FuseBridgeState::kClosing;
140*00c7fec1SAndroid Build Coastguard Worker             case ResultOrAgain::kAgain:
141*00c7fec1SAndroid Build Coastguard Worker                 return FuseBridgeState::kWaitToReadProxy;
142*00c7fec1SAndroid Build Coastguard Worker         }
143*00c7fec1SAndroid Build Coastguard Worker 
144*00c7fec1SAndroid Build Coastguard Worker         if (!buffer_.response.Write(device_fd_)) {
145*00c7fec1SAndroid Build Coastguard Worker             LogResponseError("Failed to write a reply from proxy to device", buffer_.response);
146*00c7fec1SAndroid Build Coastguard Worker             return FuseBridgeState::kClosing;
147*00c7fec1SAndroid Build Coastguard Worker         }
148*00c7fec1SAndroid Build Coastguard Worker 
149*00c7fec1SAndroid Build Coastguard Worker         auto it = opcode_map_.find(buffer_.response.header.unique);
150*00c7fec1SAndroid Build Coastguard Worker         if (it != opcode_map_.end()) {
151*00c7fec1SAndroid Build Coastguard Worker             switch (it->second) {
152*00c7fec1SAndroid Build Coastguard Worker                 case FUSE_OPEN:
153*00c7fec1SAndroid Build Coastguard Worker                     if (buffer_.response.header.error == fuse::kFuseSuccess) {
154*00c7fec1SAndroid Build Coastguard Worker                         open_count_++;
155*00c7fec1SAndroid Build Coastguard Worker                     }
156*00c7fec1SAndroid Build Coastguard Worker                     break;
157*00c7fec1SAndroid Build Coastguard Worker 
158*00c7fec1SAndroid Build Coastguard Worker                 case FUSE_RELEASE:
159*00c7fec1SAndroid Build Coastguard Worker                     if (open_count_ > 0) {
160*00c7fec1SAndroid Build Coastguard Worker                         open_count_--;
161*00c7fec1SAndroid Build Coastguard Worker                     } else {
162*00c7fec1SAndroid Build Coastguard Worker                         LOG(WARNING) << "Unexpected FUSE_RELEASE before opening a file.";
163*00c7fec1SAndroid Build Coastguard Worker                         break;
164*00c7fec1SAndroid Build Coastguard Worker                     }
165*00c7fec1SAndroid Build Coastguard Worker                     if (open_count_ == 0) {
166*00c7fec1SAndroid Build Coastguard Worker                         return FuseBridgeState::kClosing;
167*00c7fec1SAndroid Build Coastguard Worker                     }
168*00c7fec1SAndroid Build Coastguard Worker                     break;
169*00c7fec1SAndroid Build Coastguard Worker             }
170*00c7fec1SAndroid Build Coastguard Worker             opcode_map_.erase(it);
171*00c7fec1SAndroid Build Coastguard Worker         }
172*00c7fec1SAndroid Build Coastguard Worker 
173*00c7fec1SAndroid Build Coastguard Worker         return FuseBridgeState::kWaitToReadEither;
174*00c7fec1SAndroid Build Coastguard Worker     }
175*00c7fec1SAndroid Build Coastguard Worker 
ReadFromDevice(FuseBridgeLoopCallback * callback)176*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeState ReadFromDevice(FuseBridgeLoopCallback* callback) {
177*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "ReadFromDevice";
178*00c7fec1SAndroid Build Coastguard Worker         if (!buffer_.request.Read(device_fd_)) {
179*00c7fec1SAndroid Build Coastguard Worker             return FuseBridgeState::kClosing;
180*00c7fec1SAndroid Build Coastguard Worker         }
181*00c7fec1SAndroid Build Coastguard Worker 
182*00c7fec1SAndroid Build Coastguard Worker         const uint32_t opcode = buffer_.request.header.opcode;
183*00c7fec1SAndroid Build Coastguard Worker         const uint64_t unique = buffer_.request.header.unique;
184*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "Read a fuse packet, opcode=" << opcode << " unique=" << unique;
185*00c7fec1SAndroid Build Coastguard Worker         if (unique == 0) {
186*00c7fec1SAndroid Build Coastguard Worker             return FuseBridgeState::kWaitToReadEither;
187*00c7fec1SAndroid Build Coastguard Worker         }
188*00c7fec1SAndroid Build Coastguard Worker         switch (opcode) {
189*00c7fec1SAndroid Build Coastguard Worker             case FUSE_FORGET:
190*00c7fec1SAndroid Build Coastguard Worker                 // Do not reply to FUSE_FORGET.
191*00c7fec1SAndroid Build Coastguard Worker                 return FuseBridgeState::kWaitToReadEither;
192*00c7fec1SAndroid Build Coastguard Worker 
193*00c7fec1SAndroid Build Coastguard Worker             case FUSE_LOOKUP:
194*00c7fec1SAndroid Build Coastguard Worker             case FUSE_GETATTR:
195*00c7fec1SAndroid Build Coastguard Worker             case FUSE_OPEN:
196*00c7fec1SAndroid Build Coastguard Worker             case FUSE_READ:
197*00c7fec1SAndroid Build Coastguard Worker             case FUSE_WRITE:
198*00c7fec1SAndroid Build Coastguard Worker             case FUSE_RELEASE:
199*00c7fec1SAndroid Build Coastguard Worker             case FUSE_FSYNC:
200*00c7fec1SAndroid Build Coastguard Worker                 if (opcode == FUSE_OPEN || opcode == FUSE_RELEASE) {
201*00c7fec1SAndroid Build Coastguard Worker                     opcode_map_.emplace(buffer_.request.header.unique, opcode);
202*00c7fec1SAndroid Build Coastguard Worker                 }
203*00c7fec1SAndroid Build Coastguard Worker                 return WriteToProxy();
204*00c7fec1SAndroid Build Coastguard Worker 
205*00c7fec1SAndroid Build Coastguard Worker             case FUSE_INIT:
206*00c7fec1SAndroid Build Coastguard Worker                 buffer_.HandleInit();
207*00c7fec1SAndroid Build Coastguard Worker                 break;
208*00c7fec1SAndroid Build Coastguard Worker 
209*00c7fec1SAndroid Build Coastguard Worker             default:
210*00c7fec1SAndroid Build Coastguard Worker                 buffer_.HandleNotImpl();
211*00c7fec1SAndroid Build Coastguard Worker                 break;
212*00c7fec1SAndroid Build Coastguard Worker         }
213*00c7fec1SAndroid Build Coastguard Worker 
214*00c7fec1SAndroid Build Coastguard Worker         if (!buffer_.response.Write(device_fd_)) {
215*00c7fec1SAndroid Build Coastguard Worker             LogResponseError("Failed to write a response to device", buffer_.response);
216*00c7fec1SAndroid Build Coastguard Worker             return FuseBridgeState::kClosing;
217*00c7fec1SAndroid Build Coastguard Worker         }
218*00c7fec1SAndroid Build Coastguard Worker 
219*00c7fec1SAndroid Build Coastguard Worker         if (opcode == FUSE_INIT) {
220*00c7fec1SAndroid Build Coastguard Worker             callback->OnMount(mount_id_);
221*00c7fec1SAndroid Build Coastguard Worker         }
222*00c7fec1SAndroid Build Coastguard Worker 
223*00c7fec1SAndroid Build Coastguard Worker         return FuseBridgeState::kWaitToReadEither;
224*00c7fec1SAndroid Build Coastguard Worker     }
225*00c7fec1SAndroid Build Coastguard Worker 
WriteToProxy()226*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeState WriteToProxy() {
227*00c7fec1SAndroid Build Coastguard Worker         switch (buffer_.request.WriteOrAgain(proxy_fd_)) {
228*00c7fec1SAndroid Build Coastguard Worker             case ResultOrAgain::kSuccess:
229*00c7fec1SAndroid Build Coastguard Worker                 return FuseBridgeState::kWaitToReadEither;
230*00c7fec1SAndroid Build Coastguard Worker             case ResultOrAgain::kFailure:
231*00c7fec1SAndroid Build Coastguard Worker                 LOG(ERROR) << "Failed to write a request to proxy:"
232*00c7fec1SAndroid Build Coastguard Worker                            << " header.len=" << buffer_.request.header.len
233*00c7fec1SAndroid Build Coastguard Worker                            << " header.opcode=" << buffer_.request.header.opcode
234*00c7fec1SAndroid Build Coastguard Worker                            << " header.unique=" << buffer_.request.header.unique
235*00c7fec1SAndroid Build Coastguard Worker                            << " header.nodeid=" << buffer_.request.header.nodeid;
236*00c7fec1SAndroid Build Coastguard Worker                 return FuseBridgeState::kClosing;
237*00c7fec1SAndroid Build Coastguard Worker             case ResultOrAgain::kAgain:
238*00c7fec1SAndroid Build Coastguard Worker                 return FuseBridgeState::kWaitToWriteProxy;
239*00c7fec1SAndroid Build Coastguard Worker         }
240*00c7fec1SAndroid Build Coastguard Worker     }
241*00c7fec1SAndroid Build Coastguard Worker 
242*00c7fec1SAndroid Build Coastguard Worker     const int mount_id_;
243*00c7fec1SAndroid Build Coastguard Worker     base::unique_fd device_fd_;
244*00c7fec1SAndroid Build Coastguard Worker     base::unique_fd proxy_fd_;
245*00c7fec1SAndroid Build Coastguard Worker     FuseBuffer buffer_;
246*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeState state_;
247*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeState last_state_;
248*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeEntryEvent last_device_events_;
249*00c7fec1SAndroid Build Coastguard Worker     FuseBridgeEntryEvent last_proxy_events_;
250*00c7fec1SAndroid Build Coastguard Worker 
251*00c7fec1SAndroid Build Coastguard Worker     // Remember map between unique and opcode in fuse_in_header so that we can
252*00c7fec1SAndroid Build Coastguard Worker     // refer the opcode later.
253*00c7fec1SAndroid Build Coastguard Worker     std::unordered_map<uint64_t, uint32_t> opcode_map_;
254*00c7fec1SAndroid Build Coastguard Worker 
255*00c7fec1SAndroid Build Coastguard Worker     int open_count_;
256*00c7fec1SAndroid Build Coastguard Worker 
257*00c7fec1SAndroid Build Coastguard Worker     DISALLOW_COPY_AND_ASSIGN(FuseBridgeEntry);
258*00c7fec1SAndroid Build Coastguard Worker };
259*00c7fec1SAndroid Build Coastguard Worker 
260*00c7fec1SAndroid Build Coastguard Worker class BridgeEpollController : private EpollController {
261*00c7fec1SAndroid Build Coastguard Worker   public:
BridgeEpollController(base::unique_fd && poll_fd)262*00c7fec1SAndroid Build Coastguard Worker     BridgeEpollController(base::unique_fd&& poll_fd) : EpollController(std::move(poll_fd)) {}
263*00c7fec1SAndroid Build Coastguard Worker 
AddBridgePoll(FuseBridgeEntry * bridge) const264*00c7fec1SAndroid Build Coastguard Worker     bool AddBridgePoll(FuseBridgeEntry* bridge) const {
265*00c7fec1SAndroid Build Coastguard Worker         return InvokeControl(EPOLL_CTL_ADD, bridge);
266*00c7fec1SAndroid Build Coastguard Worker     }
267*00c7fec1SAndroid Build Coastguard Worker 
UpdateOrDeleteBridgePoll(FuseBridgeEntry * bridge) const268*00c7fec1SAndroid Build Coastguard Worker     bool UpdateOrDeleteBridgePoll(FuseBridgeEntry* bridge) const {
269*00c7fec1SAndroid Build Coastguard Worker         return InvokeControl(
270*00c7fec1SAndroid Build Coastguard Worker             bridge->state_ != FuseBridgeState::kClosing ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, bridge);
271*00c7fec1SAndroid Build Coastguard Worker     }
272*00c7fec1SAndroid Build Coastguard Worker 
Wait(size_t bridge_count,std::unordered_set<FuseBridgeEntry * > * entries_out)273*00c7fec1SAndroid Build Coastguard Worker     bool Wait(size_t bridge_count, std::unordered_set<FuseBridgeEntry*>* entries_out) {
274*00c7fec1SAndroid Build Coastguard Worker         CHECK(entries_out);
275*00c7fec1SAndroid Build Coastguard Worker         const size_t event_count = std::max<size_t>(bridge_count * 2, 1);
276*00c7fec1SAndroid Build Coastguard Worker         if (!EpollController::Wait(event_count)) {
277*00c7fec1SAndroid Build Coastguard Worker             return false;
278*00c7fec1SAndroid Build Coastguard Worker         }
279*00c7fec1SAndroid Build Coastguard Worker         entries_out->clear();
280*00c7fec1SAndroid Build Coastguard Worker         for (const auto& event : events()) {
281*00c7fec1SAndroid Build Coastguard Worker             FuseBridgeEntryEvent* const entry_event =
282*00c7fec1SAndroid Build Coastguard Worker                 reinterpret_cast<FuseBridgeEntryEvent*>(event.data.ptr);
283*00c7fec1SAndroid Build Coastguard Worker             entry_event->events = event.events;
284*00c7fec1SAndroid Build Coastguard Worker             entries_out->insert(entry_event->entry);
285*00c7fec1SAndroid Build Coastguard Worker         }
286*00c7fec1SAndroid Build Coastguard Worker         return true;
287*00c7fec1SAndroid Build Coastguard Worker     }
288*00c7fec1SAndroid Build Coastguard Worker 
289*00c7fec1SAndroid Build Coastguard Worker   private:
InvokeControl(int op,FuseBridgeEntry * bridge) const290*00c7fec1SAndroid Build Coastguard Worker     bool InvokeControl(int op, FuseBridgeEntry* bridge) const {
291*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "InvokeControl op=" << op << " bridge=" << bridge->mount_id_
292*00c7fec1SAndroid Build Coastguard Worker                      << " state=" << static_cast<int>(bridge->state_)
293*00c7fec1SAndroid Build Coastguard Worker                      << " last_state=" << static_cast<int>(bridge->last_state_);
294*00c7fec1SAndroid Build Coastguard Worker 
295*00c7fec1SAndroid Build Coastguard Worker         int last_device_events;
296*00c7fec1SAndroid Build Coastguard Worker         int last_proxy_events;
297*00c7fec1SAndroid Build Coastguard Worker         int device_events;
298*00c7fec1SAndroid Build Coastguard Worker         int proxy_events;
299*00c7fec1SAndroid Build Coastguard Worker         GetObservedEvents(bridge->last_state_, &last_device_events, &last_proxy_events);
300*00c7fec1SAndroid Build Coastguard Worker         GetObservedEvents(bridge->state_, &device_events, &proxy_events);
301*00c7fec1SAndroid Build Coastguard Worker         bool result = true;
302*00c7fec1SAndroid Build Coastguard Worker         if (op != EPOLL_CTL_MOD || last_device_events != device_events) {
303*00c7fec1SAndroid Build Coastguard Worker             result &= EpollController::InvokeControl(op, bridge->device_fd_, device_events,
304*00c7fec1SAndroid Build Coastguard Worker                                                      &bridge->last_device_events_);
305*00c7fec1SAndroid Build Coastguard Worker         }
306*00c7fec1SAndroid Build Coastguard Worker         if (op != EPOLL_CTL_MOD || last_proxy_events != proxy_events) {
307*00c7fec1SAndroid Build Coastguard Worker             result &= EpollController::InvokeControl(op, bridge->proxy_fd_, proxy_events,
308*00c7fec1SAndroid Build Coastguard Worker                                                      &bridge->last_proxy_events_);
309*00c7fec1SAndroid Build Coastguard Worker         }
310*00c7fec1SAndroid Build Coastguard Worker         return result;
311*00c7fec1SAndroid Build Coastguard Worker     }
312*00c7fec1SAndroid Build Coastguard Worker };
313*00c7fec1SAndroid Build Coastguard Worker 
314*00c7fec1SAndroid Build Coastguard Worker std::recursive_mutex FuseBridgeLoop::mutex_;
315*00c7fec1SAndroid Build Coastguard Worker 
FuseBridgeLoop()316*00c7fec1SAndroid Build Coastguard Worker FuseBridgeLoop::FuseBridgeLoop() : opened_(true) {
317*00c7fec1SAndroid Build Coastguard Worker     base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
318*00c7fec1SAndroid Build Coastguard Worker     if (epoll_fd.get() == -1) {
319*00c7fec1SAndroid Build Coastguard Worker         PLOG(ERROR) << "Failed to open FD for epoll";
320*00c7fec1SAndroid Build Coastguard Worker         opened_ = false;
321*00c7fec1SAndroid Build Coastguard Worker         return;
322*00c7fec1SAndroid Build Coastguard Worker     }
323*00c7fec1SAndroid Build Coastguard Worker     epoll_controller_.reset(new BridgeEpollController(std::move(epoll_fd)));
324*00c7fec1SAndroid Build Coastguard Worker }
325*00c7fec1SAndroid Build Coastguard Worker 
~FuseBridgeLoop()326*00c7fec1SAndroid Build Coastguard Worker FuseBridgeLoop::~FuseBridgeLoop() { CHECK(bridges_.empty()); }
327*00c7fec1SAndroid Build Coastguard Worker 
AddBridge(int mount_id,base::unique_fd dev_fd,base::unique_fd proxy_fd)328*00c7fec1SAndroid Build Coastguard Worker bool FuseBridgeLoop::AddBridge(int mount_id, base::unique_fd dev_fd, base::unique_fd proxy_fd) {
329*00c7fec1SAndroid Build Coastguard Worker     LOG(VERBOSE) << "Adding bridge " << mount_id;
330*00c7fec1SAndroid Build Coastguard Worker 
331*00c7fec1SAndroid Build Coastguard Worker     std::unique_ptr<FuseBridgeEntry> bridge(
332*00c7fec1SAndroid Build Coastguard Worker         new FuseBridgeEntry(mount_id, std::move(dev_fd), std::move(proxy_fd)));
333*00c7fec1SAndroid Build Coastguard Worker     std::lock_guard<std::recursive_mutex> lock(mutex_);
334*00c7fec1SAndroid Build Coastguard Worker     if (!opened_) {
335*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "Tried to add a mount to a closed bridge";
336*00c7fec1SAndroid Build Coastguard Worker         return false;
337*00c7fec1SAndroid Build Coastguard Worker     }
338*00c7fec1SAndroid Build Coastguard Worker     if (bridges_.count(mount_id)) {
339*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "Tried to add a mount point that has already been added";
340*00c7fec1SAndroid Build Coastguard Worker         return false;
341*00c7fec1SAndroid Build Coastguard Worker     }
342*00c7fec1SAndroid Build Coastguard Worker     if (!epoll_controller_->AddBridgePoll(bridge.get())) {
343*00c7fec1SAndroid Build Coastguard Worker         return false;
344*00c7fec1SAndroid Build Coastguard Worker     }
345*00c7fec1SAndroid Build Coastguard Worker 
346*00c7fec1SAndroid Build Coastguard Worker     bridges_.emplace(mount_id, std::move(bridge));
347*00c7fec1SAndroid Build Coastguard Worker     return true;
348*00c7fec1SAndroid Build Coastguard Worker }
349*00c7fec1SAndroid Build Coastguard Worker 
ProcessEventLocked(const std::unordered_set<FuseBridgeEntry * > & entries,FuseBridgeLoopCallback * callback)350*00c7fec1SAndroid Build Coastguard Worker bool FuseBridgeLoop::ProcessEventLocked(const std::unordered_set<FuseBridgeEntry*>& entries,
351*00c7fec1SAndroid Build Coastguard Worker                                         FuseBridgeLoopCallback* callback) {
352*00c7fec1SAndroid Build Coastguard Worker     for (auto entry : entries) {
353*00c7fec1SAndroid Build Coastguard Worker         entry->Transfer(callback);
354*00c7fec1SAndroid Build Coastguard Worker         if (!epoll_controller_->UpdateOrDeleteBridgePoll(entry)) {
355*00c7fec1SAndroid Build Coastguard Worker             return false;
356*00c7fec1SAndroid Build Coastguard Worker         }
357*00c7fec1SAndroid Build Coastguard Worker         if (entry->IsClosing()) {
358*00c7fec1SAndroid Build Coastguard Worker             const int mount_id = entry->mount_id();
359*00c7fec1SAndroid Build Coastguard Worker             bridges_.erase(mount_id);
360*00c7fec1SAndroid Build Coastguard Worker             callback->OnClosed(mount_id);
361*00c7fec1SAndroid Build Coastguard Worker             if (bridges_.size() == 0) {
362*00c7fec1SAndroid Build Coastguard Worker                 // All bridges are now closed.
363*00c7fec1SAndroid Build Coastguard Worker                 return false;
364*00c7fec1SAndroid Build Coastguard Worker             }
365*00c7fec1SAndroid Build Coastguard Worker         }
366*00c7fec1SAndroid Build Coastguard Worker     }
367*00c7fec1SAndroid Build Coastguard Worker     return true;
368*00c7fec1SAndroid Build Coastguard Worker }
369*00c7fec1SAndroid Build Coastguard Worker 
Start(FuseBridgeLoopCallback * callback)370*00c7fec1SAndroid Build Coastguard Worker void FuseBridgeLoop::Start(FuseBridgeLoopCallback* callback) {
371*00c7fec1SAndroid Build Coastguard Worker     LOG(DEBUG) << "Start fuse bridge loop";
372*00c7fec1SAndroid Build Coastguard Worker     std::unordered_set<FuseBridgeEntry*> entries;
373*00c7fec1SAndroid Build Coastguard Worker     while (true) {
374*00c7fec1SAndroid Build Coastguard Worker         const bool wait_result = epoll_controller_->Wait(bridges_.size(), &entries);
375*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "Receive epoll events";
376*00c7fec1SAndroid Build Coastguard Worker         {
377*00c7fec1SAndroid Build Coastguard Worker             std::lock_guard<std::recursive_mutex> lock(mutex_);
378*00c7fec1SAndroid Build Coastguard Worker             if (!(wait_result && ProcessEventLocked(entries, callback))) {
379*00c7fec1SAndroid Build Coastguard Worker                 for (auto it = bridges_.begin(); it != bridges_.end();) {
380*00c7fec1SAndroid Build Coastguard Worker                     callback->OnClosed(it->second->mount_id());
381*00c7fec1SAndroid Build Coastguard Worker                     it = bridges_.erase(it);
382*00c7fec1SAndroid Build Coastguard Worker                 }
383*00c7fec1SAndroid Build Coastguard Worker                 opened_ = false;
384*00c7fec1SAndroid Build Coastguard Worker                 return;
385*00c7fec1SAndroid Build Coastguard Worker             }
386*00c7fec1SAndroid Build Coastguard Worker         }
387*00c7fec1SAndroid Build Coastguard Worker     }
388*00c7fec1SAndroid Build Coastguard Worker }
389*00c7fec1SAndroid Build Coastguard Worker 
Lock()390*00c7fec1SAndroid Build Coastguard Worker void FuseBridgeLoop::Lock() {
391*00c7fec1SAndroid Build Coastguard Worker     mutex_.lock();
392*00c7fec1SAndroid Build Coastguard Worker }
393*00c7fec1SAndroid Build Coastguard Worker 
Unlock()394*00c7fec1SAndroid Build Coastguard Worker void FuseBridgeLoop::Unlock() {
395*00c7fec1SAndroid Build Coastguard Worker     mutex_.unlock();
396*00c7fec1SAndroid Build Coastguard Worker }
397*00c7fec1SAndroid Build Coastguard Worker 
398*00c7fec1SAndroid Build Coastguard Worker }  // namespace fuse
399*00c7fec1SAndroid Build Coastguard Worker }  // namespace android
400