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