1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "session_manager.h"
16
17 #include "prefetcher/prefetcher_daemon.h"
18 #include "prefetcher/session.h"
19 #include "prefetcher/task_id.h"
20 #include "serialize/arena_ptr.h"
21 #include "serialize/protobuf_io.h"
22
23 #include <android-base/logging.h>
24 #include <android-base/chrono_utils.h>
25 #include <android-base/unique_fd.h>
26 #include <fcntl.h>
27 #include <functional>
28 #include <stdint.h>
29 #include <sys/mman.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unordered_map>
33
34 namespace iorap {
35 namespace prefetcher {
36
operator <<(std::ostream & os,const SessionManager & manager)37 std::ostream& operator<<(std::ostream& os, const SessionManager& manager) {
38 manager.Dump(os, /*multiline*/false);
39 return os;
40 }
41
SessionManager()42 SessionManager::SessionManager() {
43 }
44
45 class SessionManagerBase : public SessionManager {
46 public:
Dump(std::ostream & os,bool multiline) const47 virtual void Dump(std::ostream& os, bool multiline) const {
48 if (!multiline) {
49 os << "SessionManager{";
50
51 os << "sessions=[";
52 for (auto it = sessions_map_.begin();
53 it != sessions_map_.end();
54 ++it) {
55 os << "(" << it->second.description << ") ";
56 it->second.session->Dump(os, /*multiline*/false);
57 }
58 os << "]";
59 return;
60 }
61
62 os << "SessionManager (session count = " << sessions_map_.size() << "):" << std::endl;
63 os << std::endl;
64
65 for (auto it = sessions_map_.begin();
66 it != sessions_map_.end();
67 ++it) {
68 os << "Description: " << it->second.description << std::endl;
69 it->second.session->Dump(os, /*multiline*/true);
70 }
71
72 // TODO: indentations? Use this pseudo line break for the time being.
73 os << "--------------------------------" << std::endl;
74 }
75
~SessionManagerBase()76 virtual ~SessionManagerBase() {}
77
FindSession(size_t session_id) const78 virtual std::shared_ptr<Session> FindSession(size_t session_id) const override {
79 auto it = sessions_map_.find(session_id);
80 if (it != sessions_map_.end()) {
81 DCHECK_EQ(session_id, it->second.SessionId());
82 return it->second.session;
83 } else {
84 return nullptr;
85 }
86 }
87
DestroySession(size_t session_id)88 virtual bool DestroySession(size_t session_id) override {
89 auto it = sessions_map_.find(session_id);
90 if (it != sessions_map_.end()) {
91 sessions_map_.erase(it);
92 return true;
93 } else {
94 return false;
95 }
96 }
97
98 protected:
InsertNewSession(std::shared_ptr<Session> session,std::string description)99 void InsertNewSession(std::shared_ptr<Session> session, std::string description) {
100 DCHECK(!FindSession(session->SessionId())) << "session cannot already exist";
101
102 size_t session_id = session->SessionId();
103
104 SessionData data;
105 data.session = std::move(session);
106 data.description = std::move(description);
107
108 sessions_map_.insert({session_id, std::move(data)});
109 }
110
111 private:
112 struct SessionData {
113 std::shared_ptr<Session> session;
114 std::string description;
115
SessionIdiorap::prefetcher::SessionManagerBase::SessionData116 size_t SessionId() const {
117 return session->SessionId();
118 }
119 };
120
121 std::unordered_map</*session_id*/size_t, SessionData> sessions_map_;
122 };
123
124 class SessionManagerDirect : public SessionManagerBase {
125 public:
CreateSession(size_t session_id,std::string description)126 virtual std::shared_ptr<Session> CreateSession(size_t session_id,
127 std::string description) override {
128 LOG(VERBOSE) << "CreateSessionDirect id=" << session_id << ", description=" << description;
129
130 std::shared_ptr<Session> session =
131 std::static_pointer_cast<Session>(std::make_shared<SessionDirect>(session_id,
132 description));
133 DCHECK(FindSession(session_id) == nullptr);
134 InsertNewSession(session, std::move(description));
135 return session;
136 }
137
SessionManagerDirect()138 SessionManagerDirect() {
139 // Intentionally left empty.
140 }
141
142 private:
143 };
144
145
146 class SessionManagerIndirect : public SessionManagerBase {
147 public:
CreateSession(size_t session_id,std::string description)148 virtual std::shared_ptr<Session> CreateSession(size_t session_id,
149 std::string description) override {
150 LOG(VERBOSE) << "CreateSessionIndirect id=" << session_id << ", description=" << description;
151
152 std::shared_ptr<Session> session =
153 std::static_pointer_cast<Session>(std::make_shared<SessionIndirect>(session_id,
154 description,
155 daemon_));
156 InsertNewSession(session, description);
157 return session;
158 }
159
SessionManagerIndirect()160 SessionManagerIndirect() : daemon_{std::make_shared<PrefetcherDaemon>()} {
161 //StartViaFork etc.
162 // TODO: also expose a 'MainLoop(...) -> daemon::Main(..)' somehow in the base interface.
163 auto params = daemon_->StartPipesViaFork();
164 if (!params) {
165 LOG(FATAL) << "Failed to fork+exec iorap.prefetcherd";
166 }
167 }
168
~SessionManagerIndirect()169 virtual ~SessionManagerIndirect() {
170 Command cmd{};
171 cmd.choice = CommandChoice::kExit;
172
173 if (!daemon_->SendCommand(cmd)) {
174 LOG(FATAL) << "Failed to nicely exit iorap.prefetcherd";
175 }
176 }
177
Dump(std::ostream & os,bool multiline) const178 virtual void Dump(std::ostream& os, bool multiline) const override {
179 Command cmd{};
180 cmd.choice = CommandChoice::kDumpEverything;
181
182 if (!daemon_->SendCommand(cmd)) {
183 LOG(ERROR) << "Failed to transmit kDumpEverything to iorap.prefetcherd";
184 }
185 }
186
187
188 private:
189 // No lifetime cycle: PrefetcherDaemon only has a SessionManagerDirect in it.
190 std::shared_ptr<PrefetcherDaemon> daemon_;
191 };
192
193 class SessionManagerIndirectSocket : public SessionManagerBase {
194 public:
CreateSession(size_t session_id,std::string description)195 virtual std::shared_ptr<Session> CreateSession(size_t session_id,
196 std::string description) override {
197 DCHECK(false) << "not supposed to create a regular session for Socket";
198
199 LOG(VERBOSE) << "CreateSessionIndirect id=" << session_id << ", description=" << description;
200
201 std::shared_ptr<Session> session =
202 std::static_pointer_cast<Session>(std::make_shared<SessionIndirect>(session_id,
203 description,
204 daemon_));
205 InsertNewSession(session, description);
206 return session;
207 }
208
CreateSession(size_t session_id,std::string description,std::optional<int> fd)209 virtual std::shared_ptr<Session> CreateSession(size_t session_id,
210 std::string description,
211 std::optional<int> fd) override {
212 CHECK(fd.has_value());
213 LOG(VERBOSE) << "CreateSessionIndirectSocket id=" << session_id
214 << ", description=" << description
215 << ", fd=" << *fd;
216
217 std::shared_ptr<Session> session =
218 std::static_pointer_cast<Session>(std::make_shared<SessionIndirectSocket>(session_id,
219 *fd,
220 description,
221 daemon_));
222 InsertNewSession(session, description);
223 return session;
224 }
225
SessionManagerIndirectSocket()226 SessionManagerIndirectSocket() : daemon_{std::make_shared<PrefetcherDaemon>()} {
227 auto params = daemon_->StartSocketViaFork();
228 if (!params) {
229 LOG(FATAL) << "Failed to fork+exec iorap.prefetcherd";
230 }
231 }
232
~SessionManagerIndirectSocket()233 virtual ~SessionManagerIndirectSocket() {
234 Command cmd{};
235 cmd.choice = CommandChoice::kExit;
236
237 if (!daemon_->SendCommand(cmd)) {
238 LOG(FATAL) << "Failed to nicely exit iorap.prefetcherd";
239 }
240 }
241
Dump(std::ostream & os,bool multiline) const242 virtual void Dump(std::ostream& os, bool multiline) const override {
243 Command cmd{};
244 cmd.choice = CommandChoice::kDumpEverything;
245
246 if (!daemon_->SendCommand(cmd)) {
247 LOG(ERROR) << "Failed to transmit kDumpEverything to iorap.prefetcherd";
248 }
249 }
250
251
252 private:
253 // No lifetime cycle: PrefetcherDaemon only has a SessionManagerDirect in it.
254 std::shared_ptr<PrefetcherDaemon> daemon_;
255 };
256
CreateManager(SessionKind kind)257 std::unique_ptr<SessionManager> SessionManager::CreateManager(SessionKind kind) {
258 LOG(VERBOSE) << "SessionManager::CreateManager kind=" << kind;
259
260 switch (kind) {
261 case SessionKind::kInProcessDirect: {
262 SessionManager* ptr = new SessionManagerDirect();
263 return std::unique_ptr<SessionManager>{ptr};
264 }
265 case SessionKind::kOutOfProcessIpc: {
266 SessionManager* ptr = new SessionManagerIndirect();
267 return std::unique_ptr<SessionManager>{ptr};
268 }
269 case SessionKind::kOutOfProcessSocket: {
270 SessionManager* ptr = new SessionManagerIndirectSocket();
271 return std::unique_ptr<SessionManager>{ptr};
272 }
273 default: {
274 LOG(FATAL) << "Invalid session kind: " << static_cast<int>(kind);
275 break;
276 }
277 }
278 }
279
280 } // namespace prefetcher
281 } // namespace iorap
282