xref: /aosp_15_r20/art/runtime/class_loader_context.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_CLASS_LOADER_CONTEXT_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_CLASS_LOADER_CONTEXT_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <string>
21*795d594fSAndroid Build Coastguard Worker #include <vector>
22*795d594fSAndroid Build Coastguard Worker #include <set>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/dchecked_vector.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file.h"
28*795d594fSAndroid Build Coastguard Worker #include "handle_scope.h"
29*795d594fSAndroid Build Coastguard Worker #include "mirror/class_loader.h"
30*795d594fSAndroid Build Coastguard Worker #include "oat/oat_file.h"
31*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change.h"
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker class DexFile;
36*795d594fSAndroid Build Coastguard Worker class OatFile;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker // Utility class which holds the class loader context used during compilation/verification.
39*795d594fSAndroid Build Coastguard Worker class EXPORT ClassLoaderContext {
40*795d594fSAndroid Build Coastguard Worker  public:
41*795d594fSAndroid Build Coastguard Worker   enum class VerificationResult {
42*795d594fSAndroid Build Coastguard Worker     kVerifies,
43*795d594fSAndroid Build Coastguard Worker     kMismatch,
44*795d594fSAndroid Build Coastguard Worker   };
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   enum ClassLoaderType {
47*795d594fSAndroid Build Coastguard Worker     kInvalidClassLoader = 0,
48*795d594fSAndroid Build Coastguard Worker     kPathClassLoader = 1,
49*795d594fSAndroid Build Coastguard Worker     kDelegateLastClassLoader = 2,
50*795d594fSAndroid Build Coastguard Worker     kInMemoryDexClassLoader = 3
51*795d594fSAndroid Build Coastguard Worker   };
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker   // Special encoding used to denote a foreign ClassLoader was found when trying to encode class
54*795d594fSAndroid Build Coastguard Worker   // loader contexts for each classpath element in a ClassLoader. See
55*795d594fSAndroid Build Coastguard Worker   // EncodeClassPathContextsForClassLoader. Keep in sync with PackageDexUsage in the framework
56*795d594fSAndroid Build Coastguard Worker   // (frameworks/base/services/core/java/com/android/server/pm/dex/PackageDexUsage.java) and
57*795d594fSAndroid Build Coastguard Worker   // DexUseManager in ART Services
58*795d594fSAndroid Build Coastguard Worker   // (art/libartservice/service/java/com/android/server/art/DexUseManager.java).
59*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kUnsupportedClassLoaderContextEncoding =
60*795d594fSAndroid Build Coastguard Worker       "=UnsupportedClassLoaderContext=";
61*795d594fSAndroid Build Coastguard Worker 
62*795d594fSAndroid Build Coastguard Worker   ~ClassLoaderContext();
63*795d594fSAndroid Build Coastguard Worker 
64*795d594fSAndroid Build Coastguard Worker   // Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files.
65*795d594fSAndroid Build Coastguard Worker   // If the dex files have been stripped, the method opens them from their oat files which are added
66*795d594fSAndroid Build Coastguard Worker   // to ClassLoaderInfo::opened_oat_files. The 'classpath_dir' argument specifies the directory to
67*795d594fSAndroid Build Coastguard Worker   // use for the relative class paths.
68*795d594fSAndroid Build Coastguard Worker   // Returns true if all dex files where successfully opened.
69*795d594fSAndroid Build Coastguard Worker   // It may be called only once per ClassLoaderContext. Subsequent calls will return the same
70*795d594fSAndroid Build Coastguard Worker   // result without doing anything.
71*795d594fSAndroid Build Coastguard Worker   // If `context_fds` is an empty vector, files will be opened using the class path locations as
72*795d594fSAndroid Build Coastguard Worker   // filenames. Otherwise `context_fds` is expected to contain file descriptors to class path dex
73*795d594fSAndroid Build Coastguard Worker   // files, following the order of dex file locations in a flattened class loader context. If their
74*795d594fSAndroid Build Coastguard Worker   // number (size of `context_fds`) does not match the number of dex files, OpenDexFiles will fail.
75*795d594fSAndroid Build Coastguard Worker   //
76*795d594fSAndroid Build Coastguard Worker   // This will replace the class path locations with the locations of the opened dex files.
77*795d594fSAndroid Build Coastguard Worker   // (Note that one dex file can contain multidexes. Each multidex will be added to the classpath
78*795d594fSAndroid Build Coastguard Worker   // separately.)
79*795d594fSAndroid Build Coastguard Worker   //
80*795d594fSAndroid Build Coastguard Worker   // only_read_checksums controls whether or not we only read the dex locations and the checksums
81*795d594fSAndroid Build Coastguard Worker   // from the apk instead of fully opening the dex files.
82*795d594fSAndroid Build Coastguard Worker   //
83*795d594fSAndroid Build Coastguard Worker   // This method is not thread safe.
84*795d594fSAndroid Build Coastguard Worker   //
85*795d594fSAndroid Build Coastguard Worker   // Note that a "false" return could mean that either an apk/jar contained no dex files or
86*795d594fSAndroid Build Coastguard Worker   // that we hit a I/O or checksum mismatch error.
87*795d594fSAndroid Build Coastguard Worker   // TODO(calin): Currently there's no easy way to tell the difference.
88*795d594fSAndroid Build Coastguard Worker   //
89*795d594fSAndroid Build Coastguard Worker   // TODO(calin): we're forced to complicate the flow in this class with a different
90*795d594fSAndroid Build Coastguard Worker   // OpenDexFiles step because the current dex2oat flow requires the dex files be opened before
91*795d594fSAndroid Build Coastguard Worker   // the class loader is created. Consider reworking the dex2oat part.
92*795d594fSAndroid Build Coastguard Worker   bool OpenDexFiles(const std::string& classpath_dir = "",
93*795d594fSAndroid Build Coastguard Worker                     const std::vector<int>& context_fds = std::vector<int>(),
94*795d594fSAndroid Build Coastguard Worker                     bool only_read_checksums = false);
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   // Remove the specified compilation sources from all classpaths present in this context.
97*795d594fSAndroid Build Coastguard Worker   // Should only be called before the first call to OpenDexFiles().
98*795d594fSAndroid Build Coastguard Worker   bool RemoveLocationsFromClassPaths(const dchecked_vector<std::string>& compilation_sources);
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker   // Creates the entire class loader hierarchy according to the current context.
101*795d594fSAndroid Build Coastguard Worker   // Returns the first class loader from the chain.
102*795d594fSAndroid Build Coastguard Worker   //
103*795d594fSAndroid Build Coastguard Worker   // For example: if the context was built from the spec
104*795d594fSAndroid Build Coastguard Worker   // "ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]..."
105*795d594fSAndroid Build Coastguard Worker   // the method returns the class loader correponding to ClassLoader1. The parent chain will be
106*795d594fSAndroid Build Coastguard Worker   // ClassLoader1 --> ClassLoader2 --> ... --> BootClassLoader.
107*795d594fSAndroid Build Coastguard Worker   //
108*795d594fSAndroid Build Coastguard Worker   // The compilation sources are appended to the classpath of the first class loader (in the above
109*795d594fSAndroid Build Coastguard Worker   // example ClassLoader1).
110*795d594fSAndroid Build Coastguard Worker   //
111*795d594fSAndroid Build Coastguard Worker   // If the context is empty, this method only creates a single PathClassLoader with the
112*795d594fSAndroid Build Coastguard Worker   // given compilation_sources.
113*795d594fSAndroid Build Coastguard Worker   //
114*795d594fSAndroid Build Coastguard Worker   // Shared libraries found in the chain will be canonicalized based on the dex files they
115*795d594fSAndroid Build Coastguard Worker   // contain.
116*795d594fSAndroid Build Coastguard Worker   //
117*795d594fSAndroid Build Coastguard Worker   // Implementation notes:
118*795d594fSAndroid Build Coastguard Worker   //   1) the objects are not completely set up. Do not use this outside of tests and the compiler.
119*795d594fSAndroid Build Coastguard Worker   //   2) should only be called before the first call to OpenDexFiles().
120*795d594fSAndroid Build Coastguard Worker   jobject CreateClassLoader(const std::vector<const DexFile*>& compilation_sources) const;
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker   // Encodes the context as a string suitable to be added in oat files.
123*795d594fSAndroid Build Coastguard Worker   // (so that it can be read and verified at runtime against the actual class
124*795d594fSAndroid Build Coastguard Worker   // loader hierarchy).
125*795d594fSAndroid Build Coastguard Worker   // Should only be called if OpenDexFiles() returned true.
126*795d594fSAndroid Build Coastguard Worker   // If stored context is non-null, the stored names are overwritten by the class path from the
127*795d594fSAndroid Build Coastguard Worker   // stored context.
128*795d594fSAndroid Build Coastguard Worker   // E.g. if the context is PCL[a.dex:b.dex] this will return
129*795d594fSAndroid Build Coastguard Worker   // "PCL[a.dex*a_checksum*b.dex*a_checksum]".
130*795d594fSAndroid Build Coastguard Worker   std::string EncodeContextForOatFile(const std::string& base_dir,
131*795d594fSAndroid Build Coastguard Worker                                       ClassLoaderContext* stored_context = nullptr) const;
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker   // Encodes the context as a string suitable to be passed to dex2oat.
134*795d594fSAndroid Build Coastguard Worker   // This is the same as EncodeContextForOatFile but without adding the checksums
135*795d594fSAndroid Build Coastguard Worker   // and only adding each dex files once (no multidex).
136*795d594fSAndroid Build Coastguard Worker   // Should only be called if OpenDexFiles() returned true.
137*795d594fSAndroid Build Coastguard Worker   std::string EncodeContextForDex2oat(const std::string& base_dir) const;
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker   // Encodes the contexts for each of the classpath elements in the child-most
140*795d594fSAndroid Build Coastguard Worker   // classloader. Under the hood EncodeContextForDex2oat is used, so no checksums
141*795d594fSAndroid Build Coastguard Worker   // will be encoded.
142*795d594fSAndroid Build Coastguard Worker   // Should only be called if the dex files are opened (either via OpenDexFiles() or by creating the
143*795d594fSAndroid Build Coastguard Worker   // context from a live class loader).
144*795d594fSAndroid Build Coastguard Worker   // Notably, for each classpath element the encoded classloader context will contain only the
145*795d594fSAndroid Build Coastguard Worker   // elements that appear before it in the containing classloader. E.g. if `this` contains
146*795d594fSAndroid Build Coastguard Worker   // (from child to parent):
147*795d594fSAndroid Build Coastguard Worker   //
148*795d594fSAndroid Build Coastguard Worker   // PathClassLoader { multidex.apk!classes.dex, multidex.apk!classes2.dex, foo.dex, bar.dex } ->
149*795d594fSAndroid Build Coastguard Worker   //    PathClassLoader { baz.dex } -> BootClassLoader
150*795d594fSAndroid Build Coastguard Worker   //
151*795d594fSAndroid Build Coastguard Worker   // then the return value will look like:
152*795d594fSAndroid Build Coastguard Worker   //
153*795d594fSAndroid Build Coastguard Worker   // `{ "multidex.apk": "PCL[];PCL[baz.dex]",
154*795d594fSAndroid Build Coastguard Worker   //    "foo.dex"     : "PCL[multidex.apk];PCL[baz.dex]",
155*795d594fSAndroid Build Coastguard Worker   //    "bar.dex"     : "PCL[multidex.apk:foo.dex];PCL[baz.dex]" }`
156*795d594fSAndroid Build Coastguard Worker   std::map<std::string, std::string> EncodeClassPathContexts(const std::string& base_dir) const;
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker   // Flattens the opened dex files into the given vector.
159*795d594fSAndroid Build Coastguard Worker   // Should only be called if OpenDexFiles() returned true.
160*795d594fSAndroid Build Coastguard Worker   std::vector<const DexFile*> FlattenOpenedDexFiles() const;
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker   // Return a list of dex file locations from this class loader context after flattening.
163*795d594fSAndroid Build Coastguard Worker   std::vector<std::string> FlattenDexPaths() const;
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker   // Verifies that the current context is identical to the context encoded as `context_spec`.
166*795d594fSAndroid Build Coastguard Worker   // Identical means:
167*795d594fSAndroid Build Coastguard Worker   //    - the number and type of the class loaders from the chain matches
168*795d594fSAndroid Build Coastguard Worker   //    - the class loader from the same position have the same classpath
169*795d594fSAndroid Build Coastguard Worker   //      (the order and checksum of the dex files matches)
170*795d594fSAndroid Build Coastguard Worker   // This should be called after OpenDexFiles() with only_read_checksums=true. There's no
171*795d594fSAndroid Build Coastguard Worker   // need to fully open the dex files if the only thing that needs to be done is to verify
172*795d594fSAndroid Build Coastguard Worker   // the context.
173*795d594fSAndroid Build Coastguard Worker   //
174*795d594fSAndroid Build Coastguard Worker   // Names are only verified if verify_names is true.
175*795d594fSAndroid Build Coastguard Worker   // Checksums are only verified if verify_checksums is true.
176*795d594fSAndroid Build Coastguard Worker   VerificationResult VerifyClassLoaderContextMatch(const std::string& context_spec,
177*795d594fSAndroid Build Coastguard Worker                                                    bool verify_names = true,
178*795d594fSAndroid Build Coastguard Worker                                                    bool verify_checksums = true) const;
179*795d594fSAndroid Build Coastguard Worker 
180*795d594fSAndroid Build Coastguard Worker   // Checks if any of the given dex files is already loaded in the current class loader context.
181*795d594fSAndroid Build Coastguard Worker   // It only checks the first class loader.
182*795d594fSAndroid Build Coastguard Worker   // Returns the list of duplicate dex files (empty if there are no duplicates).
183*795d594fSAndroid Build Coastguard Worker   std::set<const DexFile*> CheckForDuplicateDexFiles(
184*795d594fSAndroid Build Coastguard Worker       const std::vector<const DexFile*>& dex_files);
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   // Creates the class loader context from the given string.
187*795d594fSAndroid Build Coastguard Worker   // The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
188*795d594fSAndroid Build Coastguard Worker   // ClassLoaderType is either "PCL" (PathClassLoader) or "DLC" (DelegateLastClassLoader).
189*795d594fSAndroid Build Coastguard Worker   // ClasspathElem is the path of dex/jar/apk file.
190*795d594fSAndroid Build Coastguard Worker   //
191*795d594fSAndroid Build Coastguard Worker   // The spec represents a class loader chain with the natural interpretation:
192*795d594fSAndroid Build Coastguard Worker   // ClassLoader1 has ClassLoader2 as parent which has ClassLoader3 as a parent and so on.
193*795d594fSAndroid Build Coastguard Worker   // The last class loader is assumed to have the BootClassLoader as a parent.
194*795d594fSAndroid Build Coastguard Worker   //
195*795d594fSAndroid Build Coastguard Worker   // Note that we allowed class loaders with an empty class path in order to support a custom
196*795d594fSAndroid Build Coastguard Worker   // class loader for the source dex files.
197*795d594fSAndroid Build Coastguard Worker   static std::unique_ptr<ClassLoaderContext> Create(const std::string& spec);
198*795d594fSAndroid Build Coastguard Worker 
199*795d594fSAndroid Build Coastguard Worker   // Creates a context for the given class_loader and dex_elements.
200*795d594fSAndroid Build Coastguard Worker   // The method will walk the parent chain starting from `class_loader` and add their dex files
201*795d594fSAndroid Build Coastguard Worker   // to the current class loaders chain. The `dex_elements` will be added at the end of the
202*795d594fSAndroid Build Coastguard Worker   // classpath belonging to the `class_loader` argument.
203*795d594fSAndroid Build Coastguard Worker   // The ownership of the opened dex files will be retained by the given `class_loader`.
204*795d594fSAndroid Build Coastguard Worker   // If there are errors in processing the class loader chain (e.g. unsupported elements) the
205*795d594fSAndroid Build Coastguard Worker   // method returns null.
206*795d594fSAndroid Build Coastguard Worker   static std::unique_ptr<ClassLoaderContext> CreateContextForClassLoader(jobject class_loader,
207*795d594fSAndroid Build Coastguard Worker                                                                          jobjectArray dex_elements);
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker   // Returns the default class loader context to be used when none is specified.
210*795d594fSAndroid Build Coastguard Worker   // This will return a context with a single and empty PathClassLoader.
211*795d594fSAndroid Build Coastguard Worker   static std::unique_ptr<ClassLoaderContext> Default();
212*795d594fSAndroid Build Coastguard Worker 
213*795d594fSAndroid Build Coastguard Worker   // Encodes the contexts for each of the classpath elements in `class_loader`. See
214*795d594fSAndroid Build Coastguard Worker   // ClassLoaderContext::EncodeClassPathContexts for more information about the return value.
215*795d594fSAndroid Build Coastguard Worker   //
216*795d594fSAndroid Build Coastguard Worker   // If `class_loader` does not derive from BaseDexClassLoader then an empty map is returned.
217*795d594fSAndroid Build Coastguard Worker   // Otherwise if a foreign ClassLoader is found in the class loader chain then the results values
218*795d594fSAndroid Build Coastguard Worker   // will all be ClassLoaderContext::kUnsupportedClassLoaderContextEncoding.
219*795d594fSAndroid Build Coastguard Worker   static std::map<std::string, std::string> EncodeClassPathContextsForClassLoader(
220*795d594fSAndroid Build Coastguard Worker       jobject class_loader);
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker   // Returns whether `encoded_class_loader_context` is a valid encoded ClassLoaderContext or
223*795d594fSAndroid Build Coastguard Worker   // EncodedUnsupportedClassLoaderContext.
224*795d594fSAndroid Build Coastguard Worker   static bool IsValidEncoding(const std::string& possible_encoded_class_loader_context);
225*795d594fSAndroid Build Coastguard Worker 
226*795d594fSAndroid Build Coastguard Worker   struct ClassLoaderInfo {
227*795d594fSAndroid Build Coastguard Worker     // The type of this class loader.
228*795d594fSAndroid Build Coastguard Worker     ClassLoaderType type;
229*795d594fSAndroid Build Coastguard Worker     // Shared libraries this context has.
230*795d594fSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<ClassLoaderInfo>> shared_libraries;
231*795d594fSAndroid Build Coastguard Worker     // Shared libraries that will be loaded after apks code that this context has.
232*795d594fSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<ClassLoaderInfo>> shared_libraries_after;
233*795d594fSAndroid Build Coastguard Worker     // The list of class path elements that this loader loads.
234*795d594fSAndroid Build Coastguard Worker     // Note that this list may contain relative paths.
235*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> classpath;
236*795d594fSAndroid Build Coastguard Worker     // Original opened class path (ignoring multidex).
237*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> original_classpath;
238*795d594fSAndroid Build Coastguard Worker     // The list of class path elements checksums.
239*795d594fSAndroid Build Coastguard Worker     // May be empty if the checksums are not given when the context is created.
240*795d594fSAndroid Build Coastguard Worker     std::vector<uint32_t> checksums;
241*795d594fSAndroid Build Coastguard Worker     // After OpenDexFiles is called this holds the opened dex files.
242*795d594fSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
243*795d594fSAndroid Build Coastguard Worker     // After OpenDexFiles, in case some of the dex files were opened from their oat files
244*795d594fSAndroid Build Coastguard Worker     // this holds the list of opened oat files.
245*795d594fSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<OatFile>> opened_oat_files;
246*795d594fSAndroid Build Coastguard Worker     // The parent class loader.
247*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<ClassLoaderInfo> parent;
248*795d594fSAndroid Build Coastguard Worker 
ClassLoaderInfoClassLoaderInfo249*795d594fSAndroid Build Coastguard Worker     explicit ClassLoaderInfo(ClassLoaderType cl_type) : type(cl_type) {}
250*795d594fSAndroid Build Coastguard Worker   };
251*795d594fSAndroid Build Coastguard Worker 
252*795d594fSAndroid Build Coastguard Worker  private:
253*795d594fSAndroid Build Coastguard Worker   // Creates an empty context (with no class loaders).
254*795d594fSAndroid Build Coastguard Worker   ClassLoaderContext();
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker   // Get the parent of the class loader chain at depth `index`.
GetParent(size_t index)257*795d594fSAndroid Build Coastguard Worker   ClassLoaderInfo* GetParent(size_t index) const {
258*795d594fSAndroid Build Coastguard Worker     ClassLoaderInfo* result = class_loader_chain_.get();
259*795d594fSAndroid Build Coastguard Worker     while ((result != nullptr) && (index-- != 0)) {
260*795d594fSAndroid Build Coastguard Worker       result = result->parent.get();
261*795d594fSAndroid Build Coastguard Worker     }
262*795d594fSAndroid Build Coastguard Worker     return result;
263*795d594fSAndroid Build Coastguard Worker   }
264*795d594fSAndroid Build Coastguard Worker 
GetParentChainSize()265*795d594fSAndroid Build Coastguard Worker   size_t GetParentChainSize() const {
266*795d594fSAndroid Build Coastguard Worker     size_t result = 0;
267*795d594fSAndroid Build Coastguard Worker     ClassLoaderInfo* info = class_loader_chain_.get();
268*795d594fSAndroid Build Coastguard Worker     while (info != nullptr) {
269*795d594fSAndroid Build Coastguard Worker       ++result;
270*795d594fSAndroid Build Coastguard Worker       info = info->parent.get();
271*795d594fSAndroid Build Coastguard Worker     }
272*795d594fSAndroid Build Coastguard Worker     return result;
273*795d594fSAndroid Build Coastguard Worker   }
274*795d594fSAndroid Build Coastguard Worker 
275*795d594fSAndroid Build Coastguard Worker   // Constructs an empty context.
276*795d594fSAndroid Build Coastguard Worker   // `owns_the_dex_files` specifies whether or not the context will own the opened dex files
277*795d594fSAndroid Build Coastguard Worker   // present in the class loader chain. If `owns_the_dex_files` is true then OpenDexFiles cannot
278*795d594fSAndroid Build Coastguard Worker   // be called on this context (dex_files_open_attempted_ and dex_files_open_result_ will be set
279*795d594fSAndroid Build Coastguard Worker   // to true as well)
280*795d594fSAndroid Build Coastguard Worker   explicit ClassLoaderContext(bool owns_the_dex_files);
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker   // Reads the class loader spec in place and returns true if the spec is valid and the
283*795d594fSAndroid Build Coastguard Worker   // compilation context was constructed.
284*795d594fSAndroid Build Coastguard Worker   bool Parse(const std::string& spec, bool parse_checksums = false);
285*795d594fSAndroid Build Coastguard Worker   ClassLoaderInfo* ParseInternal(const std::string& spec, bool parse_checksums);
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker   // Attempts to parse a single class loader spec.
288*795d594fSAndroid Build Coastguard Worker   // Returns the ClassLoaderInfo abstraction for this spec, or null if it cannot be parsed.
289*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ClassLoaderInfo> ParseClassLoaderSpec(
290*795d594fSAndroid Build Coastguard Worker       const std::string& class_loader_spec,
291*795d594fSAndroid Build Coastguard Worker       bool parse_checksums = false);
292*795d594fSAndroid Build Coastguard Worker 
293*795d594fSAndroid Build Coastguard Worker   // CHECKs that the dex files were opened (OpenDexFiles was called and set dex_files_open_result_
294*795d594fSAndroid Build Coastguard Worker   // to true). Aborts if not. The `calling_method` is used in the log message to identify the source
295*795d594fSAndroid Build Coastguard Worker   // of the call.
296*795d594fSAndroid Build Coastguard Worker   void CheckDexFilesOpened(const std::string& calling_method) const;
297*795d594fSAndroid Build Coastguard Worker 
298*795d594fSAndroid Build Coastguard Worker   // Creates the `ClassLoaderInfo` representing`class_loader` and attach it to `this`.
299*795d594fSAndroid Build Coastguard Worker   // The dex file present in `dex_elements` array (if not null) will be added at the end of
300*795d594fSAndroid Build Coastguard Worker   // the classpath.
301*795d594fSAndroid Build Coastguard Worker   bool CreateInfoFromClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
302*795d594fSAndroid Build Coastguard Worker                                  Handle<mirror::ClassLoader> class_loader,
303*795d594fSAndroid Build Coastguard Worker                                  Handle<mirror::ObjectArray<mirror::Object>> dex_elements,
304*795d594fSAndroid Build Coastguard Worker                                  ClassLoaderInfo* child_info,
305*795d594fSAndroid Build Coastguard Worker                                  bool is_shared_library,
306*795d594fSAndroid Build Coastguard Worker                                  bool is_after)
307*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_);
308*795d594fSAndroid Build Coastguard Worker 
309*795d594fSAndroid Build Coastguard Worker   // Encodes the context as a string suitable to be passed to dex2oat or to be added to the
310*795d594fSAndroid Build Coastguard Worker   // oat file as the class path key.
311*795d594fSAndroid Build Coastguard Worker   // If for_dex2oat is true, the encoding adds each file once (i.e. it does not add multidex
312*795d594fSAndroid Build Coastguard Worker   // location). Otherwise, for oat files, the encoding adds all the dex files (including multidex)
313*795d594fSAndroid Build Coastguard Worker   // together with their checksums.
314*795d594fSAndroid Build Coastguard Worker   // Should only be called if OpenDexFiles() returned true.
315*795d594fSAndroid Build Coastguard Worker   std::string EncodeContext(const std::string& base_dir,
316*795d594fSAndroid Build Coastguard Worker                             bool for_dex2oat,
317*795d594fSAndroid Build Coastguard Worker                             ClassLoaderContext* stored_context) const;
318*795d594fSAndroid Build Coastguard Worker 
319*795d594fSAndroid Build Coastguard Worker   // Internal version of `EncodeContext`, which will be called recursively
320*795d594fSAndroid Build Coastguard Worker   // on the parent and shared libraries.
321*795d594fSAndroid Build Coastguard Worker   void EncodeContextInternal(const ClassLoaderInfo& info,
322*795d594fSAndroid Build Coastguard Worker                              const std::string& base_dir,
323*795d594fSAndroid Build Coastguard Worker                              bool for_dex2oat,
324*795d594fSAndroid Build Coastguard Worker                              ClassLoaderInfo* stored_info,
325*795d594fSAndroid Build Coastguard Worker                              std::ostringstream& out) const;
326*795d594fSAndroid Build Coastguard Worker 
327*795d594fSAndroid Build Coastguard Worker   // Encodes e.g. PCL[foo.dex:bar.dex]
328*795d594fSAndroid Build Coastguard Worker   void EncodeClassPath(const std::string& base_dir,
329*795d594fSAndroid Build Coastguard Worker                        const std::vector<std::string>& dex_locations,
330*795d594fSAndroid Build Coastguard Worker                        const std::vector<uint32_t>& checksums,
331*795d594fSAndroid Build Coastguard Worker                        ClassLoaderType type,
332*795d594fSAndroid Build Coastguard Worker                        std::ostringstream& out) const;
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker   // Encodes the shared libraries classloaders and the parent classloader if
335*795d594fSAndroid Build Coastguard Worker   // either are present in info, e.g. {PCL[foo.dex]#PCL[bar.dex]};PCL[baz.dex]
336*795d594fSAndroid Build Coastguard Worker   void EncodeSharedLibAndParent(const ClassLoaderInfo& info,
337*795d594fSAndroid Build Coastguard Worker                                 const std::string& base_dir,
338*795d594fSAndroid Build Coastguard Worker                                 bool for_dex2oat,
339*795d594fSAndroid Build Coastguard Worker                                 ClassLoaderInfo* stored_info,
340*795d594fSAndroid Build Coastguard Worker                                 std::ostringstream& out) const;
341*795d594fSAndroid Build Coastguard Worker 
342*795d594fSAndroid Build Coastguard Worker   bool ClassLoaderInfoMatch(const ClassLoaderInfo& info,
343*795d594fSAndroid Build Coastguard Worker                             const ClassLoaderInfo& expected_info,
344*795d594fSAndroid Build Coastguard Worker                             const std::string& context_spec,
345*795d594fSAndroid Build Coastguard Worker                             bool verify_names,
346*795d594fSAndroid Build Coastguard Worker                             bool verify_checksums) const;
347*795d594fSAndroid Build Coastguard Worker 
348*795d594fSAndroid Build Coastguard Worker   // Extracts the class loader type from the given spec.
349*795d594fSAndroid Build Coastguard Worker   // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not
350*795d594fSAndroid Build Coastguard Worker   // recognized.
351*795d594fSAndroid Build Coastguard Worker   static ClassLoaderType ExtractClassLoaderType(const std::string& class_loader_spec);
352*795d594fSAndroid Build Coastguard Worker 
353*795d594fSAndroid Build Coastguard Worker   // Returns the string representation of the class loader type.
354*795d594fSAndroid Build Coastguard Worker   // The returned format can be used when parsing a context spec.
355*795d594fSAndroid Build Coastguard Worker   static const char* GetClassLoaderTypeName(ClassLoaderType type);
356*795d594fSAndroid Build Coastguard Worker 
357*795d594fSAndroid Build Coastguard Worker   // Encodes the state of processing the dex files associated with the context.
358*795d594fSAndroid Build Coastguard Worker   enum ContextDexFilesState {
359*795d594fSAndroid Build Coastguard Worker     // The dex files are not opened.
360*795d594fSAndroid Build Coastguard Worker     kDexFilesNotOpened = 1,
361*795d594fSAndroid Build Coastguard Worker     // The dex checksums/locations were read from the apk/dex but the dex files were not opened.
362*795d594fSAndroid Build Coastguard Worker     kDexFilesChecksumsRead = 2,
363*795d594fSAndroid Build Coastguard Worker     // The dex files are opened (either because we called OpenDexFiles, or we used a class loader
364*795d594fSAndroid Build Coastguard Worker     // to create the context). This implies kDexFilesChecksumsRead.
365*795d594fSAndroid Build Coastguard Worker     kDexFilesOpened = 3,
366*795d594fSAndroid Build Coastguard Worker     // We failed to open the dex files or read the checksums.
367*795d594fSAndroid Build Coastguard Worker     kDexFilesOpenFailed = 4
368*795d594fSAndroid Build Coastguard Worker   };
369*795d594fSAndroid Build Coastguard Worker 
370*795d594fSAndroid Build Coastguard Worker   // The class loader chain.
371*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<ClassLoaderInfo> class_loader_chain_;
372*795d594fSAndroid Build Coastguard Worker 
373*795d594fSAndroid Build Coastguard Worker   // The opening state of the dex files.
374*795d594fSAndroid Build Coastguard Worker   ContextDexFilesState dex_files_state_;
375*795d594fSAndroid Build Coastguard Worker 
376*795d594fSAndroid Build Coastguard Worker   // Whether or not the context owns the opened dex and oat files.
377*795d594fSAndroid Build Coastguard Worker   // If true, the opened dex files will be de-allocated when the context is destructed.
378*795d594fSAndroid Build Coastguard Worker   // If false, the objects will continue to be alive.
379*795d594fSAndroid Build Coastguard Worker   // Note that for convenience the the opened dex/oat files are stored as unique pointers
380*795d594fSAndroid Build Coastguard Worker   // which will release their ownership in the destructor based on this flag.
381*795d594fSAndroid Build Coastguard Worker   const bool owns_the_dex_files_;
382*795d594fSAndroid Build Coastguard Worker 
383*795d594fSAndroid Build Coastguard Worker   friend class ClassLoaderContextTest;
384*795d594fSAndroid Build Coastguard Worker 
385*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(ClassLoaderContext);
386*795d594fSAndroid Build Coastguard Worker };
387*795d594fSAndroid Build Coastguard Worker 
388*795d594fSAndroid Build Coastguard Worker }  // namespace art
389*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_CLASS_LOADER_CONTEXT_H_
390