• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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