• 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 "inode2filename/inode_resolver.h"
16 
17 #include "common/cmd_utils.h"
18 #include "inode2filename/out_of_process_inode_resolver.h"
19 #include "inode2filename/search_directories.h"
20 
21 #include <android-base/logging.h>
22 
23 #include <fstream>
24 #include <stdio.h>
25 
26 namespace rx = rxcpp;
27 
28 namespace iorap::inode2filename {
29 
ToArgs(ProcessMode process_mode)30 std::vector<std::string> ToArgs(ProcessMode process_mode) {
31   const char* value = nullptr;
32 
33   switch (process_mode) {
34     case ProcessMode::kInProcessDirect:
35       value = "in";
36       break;
37     case ProcessMode::kInProcessIpc:
38       value = "in-ipc";
39       break;
40     case ProcessMode::kOutOfProcessIpc:
41       value = "out";
42       break;
43   }
44 
45   std::vector<std::string> args;
46   iorap::common::AppendNamedArg(args, "--process-mode", value);
47   return args;
48 }
49 
ToArgs(VerifyKind verify_kind)50 std::vector<std::string> ToArgs(VerifyKind verify_kind) {
51   const char* value = nullptr;
52 
53   switch (verify_kind) {
54     case VerifyKind::kNone:
55       value = "none";
56       break;
57     case VerifyKind::kStat:
58       value = "stat";
59       break;
60   }
61 
62   std::vector<std::string> args;
63   iorap::common::AppendNamedArg(args, "--verify", value);
64   return args;
65 }
66 
ToArgs(const InodeResolverDependencies & deps)67 std::vector<std::string> ToArgs(const InodeResolverDependencies& deps) {
68   std::vector<std::string> args = ToArgs(*static_cast<const DataSourceDependencies*>(&deps));
69   iorap::common::AppendArgsRepeatedly(args, ToArgs(deps.process_mode));
70   iorap::common::AppendArgsRepeatedly(args, ToArgs(deps.verify));
71 
72   return args;
73 }
74 
75 struct InodeResolver::Impl {
Impliorap::inode2filename::InodeResolver::Impl76   Impl(InodeResolverDependencies dependencies)
77     : dependencies_{std::move(dependencies)} {
78     DCHECK(dependencies_.system_call != nullptr);
79     data_source_ = DataSource::Create(/*downcast*/dependencies_);
80   }
Impliorap::inode2filename::InodeResolver::Impl81   Impl(InodeResolverDependencies dependencies, std::shared_ptr<DataSource> data_source)
82     : dependencies_{std::move(dependencies)} {
83     DCHECK(dependencies_.system_call != nullptr);
84     data_source_ = std::move(data_source);
85     DCHECK(data_source_ != nullptr);
86   }
87   InodeResolverDependencies dependencies_;
88   std::shared_ptr<DataSource> data_source_;
89 };
90 
InodeResolver(InodeResolverDependencies dependencies)91 InodeResolver::InodeResolver(InodeResolverDependencies dependencies)
92   : impl_(new InodeResolver::Impl{std::move(dependencies)}) {
93 }
94 
InodeResolver(InodeResolverDependencies dependencies,std::shared_ptr<DataSource> data_source)95 InodeResolver::InodeResolver(InodeResolverDependencies dependencies,
96                              std::shared_ptr<DataSource> data_source)
97   : impl_(new InodeResolver::Impl{std::move(dependencies), std::move(data_source)}) {
98 }
99 
Create(InodeResolverDependencies dependencies)100 std::shared_ptr<InodeResolver> InodeResolver::Create(InodeResolverDependencies dependencies) {
101   if (dependencies.process_mode == ProcessMode::kInProcessDirect) {
102     return std::shared_ptr<InodeResolver>{
103         new InodeResolver{std::move(dependencies)}};
104   } else if (dependencies.process_mode == ProcessMode::kOutOfProcessIpc) {
105     return std::shared_ptr<InodeResolver>{
106         new OutOfProcessInodeResolver{std::move(dependencies)}};
107   } else {
108     CHECK(false);
109   }
110   return nullptr;
111 }
112 
Create(InodeResolverDependencies dependencies,std::shared_ptr<DataSource> data_source)113 std::shared_ptr<InodeResolver> InodeResolver::Create(InodeResolverDependencies dependencies,
114                                                      std::shared_ptr<DataSource> data_source) {
115   if (dependencies.process_mode == ProcessMode::kInProcessDirect) {
116     return std::shared_ptr<InodeResolver>{
117         new InodeResolver{std::move(dependencies), std::move(data_source)}};
118   } else if (dependencies.process_mode == ProcessMode::kOutOfProcessIpc) {
119     CHECK(false);  // directly providing a DataSource only makes sense in-process
120   } else {
121     CHECK(false);
122   }
123   return nullptr;
124 }
125 
126 rxcpp::observable<InodeResult>
FindFilenamesFromInodes(rxcpp::observable<Inode> inodes) const127     InodeResolver::FindFilenamesFromInodes(rxcpp::observable<Inode> inodes) const {
128 
129   // It's inefficient to search for inodes until the full search list is available,
130   // so first reduce to a vector so we can access all the inodes simultaneously.
131   return inodes.reduce(std::vector<Inode>{},
132                        [](std::vector<Inode> vec, Inode inode) {
133                          vec.push_back(inode);
134                          return vec;
135                        },
136                        [](std::vector<Inode> v) {
137                          return v;  // TODO: use an identity function
138                        })
139     .flat_map([self=shared_from_this()](std::vector<Inode> vec) {
140       // All borrowed values (e.g. SystemCall) must outlive the observable.
141       return self->FindFilenamesFromInodes(vec);
142     }
143   );
144 }
145 
146 rxcpp::observable<InodeResult>
FindFilenamesFromInodes(std::vector<Inode> inodes) const147 InodeResolver::FindFilenamesFromInodes(std::vector<Inode> inodes) const {
148   const DataSource& data_source = *impl_->data_source_;
149   const InodeResolverDependencies& dependencies = impl_->dependencies_;
150 
151   // Get lazy list of inodes from the data source.
152   rxcpp::observable<InodeResult> all_inodes = impl_->data_source_->EmitInodes();
153 
154   // Filter it according to the source+dependency requirements.
155   // Unsubscribe from 'all_inodes' early if all inodes are matched early.
156   const bool needs_device_number = !data_source.ResultIncludesDeviceNumber();
157   const bool needs_verification = dependencies.verify == VerifyKind::kStat;
158   SearchDirectories search{impl_->dependencies_.system_call};
159   return search.FilterFilenamesForSpecificInodes(all_inodes,
160                                                  inodes,
161                                                  needs_device_number,
162                                                  needs_verification);
163 }
164 
165 rxcpp::observable<InodeResult>
EmitAll() const166 InodeResolver::EmitAll() const {
167   const DataSource& data_source = *impl_->data_source_;
168   const InodeResolverDependencies& dependencies = impl_->dependencies_;
169 
170   // Get lazy list of inodes from the data source.
171   rxcpp::observable<InodeResult> all_inodes = impl_->data_source_->EmitInodes();
172 
173   // Apply verification and fill-in missing device numbers.
174   const bool needs_device_number = !data_source.ResultIncludesDeviceNumber();
175   const bool needs_verification = dependencies.verify == VerifyKind::kStat;
176   SearchDirectories search{impl_->dependencies_.system_call};
177   return search.EmitAllFilenames(all_inodes,
178                                  needs_device_number,
179                                  needs_verification);
180 }
181 
~InodeResolver()182 InodeResolver::~InodeResolver() {
183   // std::unique_ptr requires complete types, but we hide the definition in the header.
184   delete impl_;
185   // XX: Does this work if we just force the dtor definition into the .cc file with a unique_ptr?
186 }
187 
GetDependencies()188 InodeResolverDependencies& InodeResolver::GetDependencies() {
189   return impl_->dependencies_;
190 }
191 
GetDependencies() const192 const InodeResolverDependencies& InodeResolver::GetDependencies() const {
193   return impl_->dependencies_;
194 }
195 
StartRecording()196 void InodeResolver::StartRecording() {
197   impl_->data_source_->StartRecording();
198 }
199 
StopRecording()200 void InodeResolver::StopRecording() {
201   impl_->data_source_->StopRecording();
202 }
203 
204 // TODO: refactor more code from search_directories into this file.
205 // XX: do we also need a DataSink class? lets see if recording gets more complicated.
206 
207 }  // namespace iorap::inode2filename
208