class_loader_context.cc revision 013fd8073f3ece22b0bba1853d3f3430c8a9e4bd
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#include "class_loader_context.h"
18
19#include "art_field-inl.h"
20#include "base/dchecked_vector.h"
21#include "base/stl_util.h"
22#include "class_linker.h"
23#include "class_loader_utils.h"
24#include "dex/art_dex_file_loader.h"
25#include "dex/dex_file.h"
26#include "dex/dex_file_loader.h"
27#include "handle_scope-inl.h"
28#include "jni_internal.h"
29#include "oat_file_assistant.h"
30#include "obj_ptr-inl.h"
31#include "runtime.h"
32#include "scoped_thread_state_change-inl.h"
33#include "thread.h"
34#include "well_known_classes.h"
35
36namespace art {
37
38static constexpr char kPathClassLoaderString[] = "PCL";
39static constexpr char kDelegateLastClassLoaderString[] = "DLC";
40static constexpr char kClassLoaderOpeningMark = '[';
41static constexpr char kClassLoaderClosingMark = ']';
42static constexpr char kClassLoaderSeparator = ';';
43static constexpr char kClasspathSeparator = ':';
44static constexpr char kDexFileChecksumSeparator = '*';
45
46ClassLoaderContext::ClassLoaderContext()
47    : special_shared_library_(false),
48      dex_files_open_attempted_(false),
49      dex_files_open_result_(false),
50      owns_the_dex_files_(true) {}
51
52ClassLoaderContext::ClassLoaderContext(bool owns_the_dex_files)
53    : special_shared_library_(false),
54      dex_files_open_attempted_(true),
55      dex_files_open_result_(true),
56      owns_the_dex_files_(owns_the_dex_files) {}
57
58ClassLoaderContext::~ClassLoaderContext() {
59  if (!owns_the_dex_files_) {
60    // If the context does not own the dex/oat files release the unique pointers to
61    // make sure we do not de-allocate them.
62    for (ClassLoaderInfo& info : class_loader_chain_) {
63      for (std::unique_ptr<OatFile>& oat_file : info.opened_oat_files) {
64        oat_file.release();
65      }
66      for (std::unique_ptr<const DexFile>& dex_file : info.opened_dex_files) {
67        dex_file.release();
68      }
69    }
70  }
71}
72
73std::unique_ptr<ClassLoaderContext> ClassLoaderContext::Default() {
74  return Create("");
75}
76
77std::unique_ptr<ClassLoaderContext> ClassLoaderContext::Create(const std::string& spec) {
78  std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext());
79  if (result->Parse(spec)) {
80    return result;
81  } else {
82    return nullptr;
83  }
84}
85
86// The expected format is: "ClassLoaderType1[ClasspathElem1*Checksum1:ClasspathElem2*Checksum2...]".
87// The checksum part of the format is expected only if parse_cheksums is true.
88bool ClassLoaderContext::ParseClassLoaderSpec(const std::string& class_loader_spec,
89                                              ClassLoaderType class_loader_type,
90                                              bool parse_checksums) {
91  const char* class_loader_type_str = GetClassLoaderTypeName(class_loader_type);
92  size_t type_str_size = strlen(class_loader_type_str);
93
94  CHECK_EQ(0, class_loader_spec.compare(0, type_str_size, class_loader_type_str));
95
96  // Check the opening and closing markers.
97  if (class_loader_spec[type_str_size] != kClassLoaderOpeningMark) {
98    return false;
99  }
100  if (class_loader_spec[class_loader_spec.length() - 1] != kClassLoaderClosingMark) {
101    return false;
102  }
103
104  // At this point we know the format is ok; continue and extract the classpath.
105  // Note that class loaders with an empty class path are allowed.
106  std::string classpath = class_loader_spec.substr(type_str_size + 1,
107                                                   class_loader_spec.length() - type_str_size - 2);
108
109  class_loader_chain_.push_back(ClassLoaderInfo(class_loader_type));
110
111  if (!parse_checksums) {
112    Split(classpath, kClasspathSeparator, &class_loader_chain_.back().classpath);
113  } else {
114    std::vector<std::string> classpath_elements;
115    Split(classpath, kClasspathSeparator, &classpath_elements);
116    for (const std::string& element : classpath_elements) {
117      std::vector<std::string> dex_file_with_checksum;
118      Split(element, kDexFileChecksumSeparator, &dex_file_with_checksum);
119      if (dex_file_with_checksum.size() != 2) {
120        return false;
121      }
122      uint32_t checksum = 0;
123      if (!ParseInt(dex_file_with_checksum[1].c_str(), &checksum)) {
124        return false;
125      }
126      class_loader_chain_.back().classpath.push_back(dex_file_with_checksum[0]);
127      class_loader_chain_.back().checksums.push_back(checksum);
128    }
129  }
130
131  return true;
132}
133
134// Extracts the class loader type from the given spec.
135// Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not
136// recognized.
137ClassLoaderContext::ClassLoaderType
138ClassLoaderContext::ExtractClassLoaderType(const std::string& class_loader_spec) {
139  const ClassLoaderType kValidTypes[] = {kPathClassLoader, kDelegateLastClassLoader};
140  for (const ClassLoaderType& type : kValidTypes) {
141    const char* type_str = GetClassLoaderTypeName(type);
142    if (class_loader_spec.compare(0, strlen(type_str), type_str) == 0) {
143      return type;
144    }
145  }
146  return kInvalidClassLoader;
147}
148
149// The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
150// ClassLoaderType is either "PCL" (PathClassLoader) or "DLC" (DelegateLastClassLoader).
151// ClasspathElem is the path of dex/jar/apk file.
152bool ClassLoaderContext::Parse(const std::string& spec, bool parse_checksums) {
153  if (spec.empty()) {
154    // By default we load the dex files in a PathClassLoader.
155    // So an empty spec is equivalent to an empty PathClassLoader (this happens when running
156    // tests)
157    class_loader_chain_.push_back(ClassLoaderInfo(kPathClassLoader));
158    return true;
159  }
160
161  // Stop early if we detect the special shared library, which may be passed as the classpath
162  // for dex2oat when we want to skip the shared libraries check.
163  if (spec == OatFile::kSpecialSharedLibrary) {
164    LOG(INFO) << "The ClassLoaderContext is a special shared library.";
165    special_shared_library_ = true;
166    return true;
167  }
168
169  std::vector<std::string> class_loaders;
170  Split(spec, kClassLoaderSeparator, &class_loaders);
171
172  for (const std::string& class_loader : class_loaders) {
173    ClassLoaderType type = ExtractClassLoaderType(class_loader);
174    if (type == kInvalidClassLoader) {
175      LOG(ERROR) << "Invalid class loader type: " << class_loader;
176      return false;
177    }
178    if (!ParseClassLoaderSpec(class_loader, type, parse_checksums)) {
179      LOG(ERROR) << "Invalid class loader spec: " << class_loader;
180      return false;
181    }
182  }
183  return true;
184}
185
186// Opens requested class path files and appends them to opened_dex_files. If the dex files have
187// been stripped, this opens them from their oat files (which get added to opened_oat_files).
188bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& classpath_dir) {
189  if (dex_files_open_attempted_) {
190    // Do not attempt to re-open the files if we already tried.
191    return dex_files_open_result_;
192  }
193
194  dex_files_open_attempted_ = true;
195  // Assume we can open all dex files. If not, we will set this to false as we go.
196  dex_files_open_result_ = true;
197
198  if (special_shared_library_) {
199    // Nothing to open if the context is a special shared library.
200    return true;
201  }
202
203  // Note that we try to open all dex files even if some fail.
204  // We may get resource-only apks which we cannot load.
205  // TODO(calin): Refine the dex opening interface to be able to tell if an archive contains
206  // no dex files. So that we can distinguish the real failures...
207  const ArtDexFileLoader dex_file_loader;
208  for (ClassLoaderInfo& info : class_loader_chain_) {
209    size_t opened_dex_files_index = info.opened_dex_files.size();
210    for (const std::string& cp_elem : info.classpath) {
211      // If path is relative, append it to the provided base directory.
212      std::string location = cp_elem;
213      if (location[0] != '/' && !classpath_dir.empty()) {
214        location = classpath_dir + (classpath_dir.back() == '/' ? "" : "/") + location;
215      }
216
217      std::string error_msg;
218      // When opening the dex files from the context we expect their checksum to match their
219      // contents. So pass true to verify_checksum.
220      if (!dex_file_loader.Open(location.c_str(),
221                                location.c_str(),
222                                Runtime::Current()->IsVerificationEnabled(),
223                                /*verify_checksum*/ true,
224                                &error_msg,
225                                &info.opened_dex_files)) {
226        // If we fail to open the dex file because it's been stripped, try to open the dex file
227        // from its corresponding oat file.
228        // This could happen when we need to recompile a pre-build whose dex code has been stripped.
229        // (for example, if the pre-build is only quicken and we want to re-compile it
230        // speed-profile).
231        // TODO(calin): Use the vdex directly instead of going through the oat file.
232        OatFileAssistant oat_file_assistant(location.c_str(), isa, false);
233        std::unique_ptr<OatFile> oat_file(oat_file_assistant.GetBestOatFile());
234        std::vector<std::unique_ptr<const DexFile>> oat_dex_files;
235        if (oat_file != nullptr &&
236            OatFileAssistant::LoadDexFiles(*oat_file, location, &oat_dex_files)) {
237          info.opened_oat_files.push_back(std::move(oat_file));
238          info.opened_dex_files.insert(info.opened_dex_files.end(),
239                                       std::make_move_iterator(oat_dex_files.begin()),
240                                       std::make_move_iterator(oat_dex_files.end()));
241        } else {
242          LOG(WARNING) << "Could not open dex files from location: " << location;
243          dex_files_open_result_ = false;
244        }
245      }
246    }
247
248    // We finished opening the dex files from the classpath.
249    // Now update the classpath and the checksum with the locations of the dex files.
250    //
251    // We do this because initially the classpath contains the paths of the dex files; and
252    // some of them might be multi-dexes. So in order to have a consistent view we replace all the
253    // file paths with the actual dex locations being loaded.
254    // This will allow the context to VerifyClassLoaderContextMatch which expects or multidex
255    // location in the class paths.
256    // Note that this will also remove the paths that could not be opened.
257    info.classpath.clear();
258    info.checksums.clear();
259    for (size_t k = opened_dex_files_index; k < info.opened_dex_files.size(); k++) {
260      std::unique_ptr<const DexFile>& dex = info.opened_dex_files[k];
261      info.classpath.push_back(dex->GetLocation());
262      info.checksums.push_back(dex->GetLocationChecksum());
263    }
264  }
265
266  return dex_files_open_result_;
267}
268
269bool ClassLoaderContext::RemoveLocationsFromClassPaths(
270    const dchecked_vector<std::string>& locations) {
271  CHECK(!dex_files_open_attempted_)
272      << "RemoveLocationsFromClasspaths cannot be call after OpenDexFiles";
273
274  std::set<std::string> canonical_locations;
275  for (const std::string& location : locations) {
276    canonical_locations.insert(DexFileLoader::GetDexCanonicalLocation(location.c_str()));
277  }
278  bool removed_locations = false;
279  for (ClassLoaderInfo& info : class_loader_chain_) {
280    size_t initial_size = info.classpath.size();
281    auto kept_it = std::remove_if(
282        info.classpath.begin(),
283        info.classpath.end(),
284        [canonical_locations](const std::string& location) {
285            return ContainsElement(canonical_locations,
286                                   DexFileLoader::GetDexCanonicalLocation(location.c_str()));
287        });
288    info.classpath.erase(kept_it, info.classpath.end());
289    if (initial_size != info.classpath.size()) {
290      removed_locations = true;
291    }
292  }
293  return removed_locations;
294}
295
296std::string ClassLoaderContext::EncodeContextForDex2oat(const std::string& base_dir) const {
297  return EncodeContext(base_dir, /*for_dex2oat*/ true);
298}
299
300std::string ClassLoaderContext::EncodeContextForOatFile(const std::string& base_dir) const {
301  return EncodeContext(base_dir, /*for_dex2oat*/ false);
302}
303
304std::string ClassLoaderContext::EncodeContext(const std::string& base_dir,
305                                              bool for_dex2oat) const {
306  CheckDexFilesOpened("EncodeContextForOatFile");
307  if (special_shared_library_) {
308    return OatFile::kSpecialSharedLibrary;
309  }
310
311  std::ostringstream out;
312  if (class_loader_chain_.empty()) {
313    // We can get in this situation if the context was created with a class path containing the
314    // source dex files which were later removed (happens during run-tests).
315    out << GetClassLoaderTypeName(kPathClassLoader)
316        << kClassLoaderOpeningMark
317        << kClassLoaderClosingMark;
318    return out.str();
319  }
320
321  for (size_t i = 0; i < class_loader_chain_.size(); i++) {
322    const ClassLoaderInfo& info = class_loader_chain_[i];
323    if (i > 0) {
324      out << kClassLoaderSeparator;
325    }
326    out << GetClassLoaderTypeName(info.type);
327    out << kClassLoaderOpeningMark;
328    std::set<std::string> seen_locations;
329    for (size_t k = 0; k < info.opened_dex_files.size(); k++) {
330      const std::unique_ptr<const DexFile>& dex_file = info.opened_dex_files[k];
331      if (for_dex2oat) {
332        // dex2oat only needs the base location. It cannot accept multidex locations.
333        // So ensure we only add each file once.
334        bool new_insert = seen_locations.insert(
335            DexFileLoader::GetBaseLocation(dex_file->GetLocation())).second;
336        if (!new_insert) {
337          continue;
338        }
339      }
340      const std::string& location = dex_file->GetLocation();
341      if (k > 0) {
342        out << kClasspathSeparator;
343      }
344      // Find paths that were relative and convert them back from absolute.
345      if (!base_dir.empty() && location.substr(0, base_dir.length()) == base_dir) {
346        out << location.substr(base_dir.length() + 1).c_str();
347      } else {
348        out << dex_file->GetLocation().c_str();
349      }
350      // dex2oat does not need the checksums.
351      if (!for_dex2oat) {
352        out << kDexFileChecksumSeparator;
353        out << dex_file->GetLocationChecksum();
354      }
355    }
356    out << kClassLoaderClosingMark;
357  }
358  return out.str();
359}
360
361jobject ClassLoaderContext::CreateClassLoader(
362    const std::vector<const DexFile*>& compilation_sources) const {
363  CheckDexFilesOpened("CreateClassLoader");
364
365  Thread* self = Thread::Current();
366  ScopedObjectAccess soa(self);
367
368  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
369
370  if (class_loader_chain_.empty()) {
371    return class_linker->CreatePathClassLoader(self, compilation_sources);
372  }
373
374  // Create the class loaders starting from the top most parent (the one on the last position
375  // in the chain) but omit the first class loader which will contain the compilation_sources and
376  // needs special handling.
377  jobject current_parent = nullptr;  // the starting parent is the BootClassLoader.
378  for (size_t i = class_loader_chain_.size() - 1; i > 0; i--) {
379    std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(
380        class_loader_chain_[i].opened_dex_files);
381    current_parent = class_linker->CreateWellKnownClassLoader(
382        self,
383        class_path_files,
384        GetClassLoaderClass(class_loader_chain_[i].type),
385        current_parent);
386  }
387
388  // We set up all the parents. Move on to create the first class loader.
389  // Its classpath comes first, followed by compilation sources. This ensures that whenever
390  // we need to resolve classes from it the classpath elements come first.
391
392  std::vector<const DexFile*> first_class_loader_classpath = MakeNonOwningPointerVector(
393      class_loader_chain_[0].opened_dex_files);
394  first_class_loader_classpath.insert(first_class_loader_classpath.end(),
395                                    compilation_sources.begin(),
396                                    compilation_sources.end());
397
398  return class_linker->CreateWellKnownClassLoader(
399      self,
400      first_class_loader_classpath,
401      GetClassLoaderClass(class_loader_chain_[0].type),
402      current_parent);
403}
404
405std::vector<const DexFile*> ClassLoaderContext::FlattenOpenedDexFiles() const {
406  CheckDexFilesOpened("FlattenOpenedDexFiles");
407
408  std::vector<const DexFile*> result;
409  for (const ClassLoaderInfo& info : class_loader_chain_) {
410    for (const std::unique_ptr<const DexFile>& dex_file : info.opened_dex_files) {
411      result.push_back(dex_file.get());
412    }
413  }
414  return result;
415}
416
417const char* ClassLoaderContext::GetClassLoaderTypeName(ClassLoaderType type) {
418  switch (type) {
419    case kPathClassLoader: return kPathClassLoaderString;
420    case kDelegateLastClassLoader: return kDelegateLastClassLoaderString;
421    default:
422      LOG(FATAL) << "Invalid class loader type " << type;
423      UNREACHABLE();
424  }
425}
426
427void ClassLoaderContext::CheckDexFilesOpened(const std::string& calling_method) const {
428  CHECK(dex_files_open_attempted_)
429      << "Dex files were not successfully opened before the call to " << calling_method
430      << "attempt=" << dex_files_open_attempted_ << ", result=" << dex_files_open_result_;
431}
432
433// Collects the dex files from the give Java dex_file object. Only the dex files with
434// at least 1 class are collected. If a null java_dex_file is passed this method does nothing.
435static bool CollectDexFilesFromJavaDexFile(ObjPtr<mirror::Object> java_dex_file,
436                                           ArtField* const cookie_field,
437                                           std::vector<const DexFile*>* out_dex_files)
438      REQUIRES_SHARED(Locks::mutator_lock_) {
439  if (java_dex_file == nullptr) {
440    return true;
441  }
442  // On the Java side, the dex files are stored in the cookie field.
443  mirror::LongArray* long_array = cookie_field->GetObject(java_dex_file)->AsLongArray();
444  if (long_array == nullptr) {
445    // This should never happen so log a warning.
446    LOG(ERROR) << "Unexpected null cookie";
447    return false;
448  }
449  int32_t long_array_size = long_array->GetLength();
450  // Index 0 from the long array stores the oat file. The dex files start at index 1.
451  for (int32_t j = 1; j < long_array_size; ++j) {
452    const DexFile* cp_dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(
453        long_array->GetWithoutChecks(j)));
454    if (cp_dex_file != nullptr && cp_dex_file->NumClassDefs() > 0) {
455      // TODO(calin): It's unclear why the dex files with no classes are skipped here and when
456      // cp_dex_file can be null.
457      out_dex_files->push_back(cp_dex_file);
458    }
459  }
460  return true;
461}
462
463// Collects all the dex files loaded by the given class loader.
464// Returns true for success or false if an unexpected state is discovered (e.g. a null dex cookie,
465// a null list of dex elements or a null dex element).
466static bool CollectDexFilesFromSupportedClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
467                                                    Handle<mirror::ClassLoader> class_loader,
468                                                    std::vector<const DexFile*>* out_dex_files)
469      REQUIRES_SHARED(Locks::mutator_lock_) {
470  CHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader));
471
472  // All supported class loaders inherit from BaseDexClassLoader.
473  // We need to get the DexPathList and loop through it.
474  ArtField* const cookie_field =
475      jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
476  ArtField* const dex_file_field =
477      jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
478  ObjPtr<mirror::Object> dex_path_list =
479      jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList)->
480          GetObject(class_loader.Get());
481  CHECK(cookie_field != nullptr);
482  CHECK(dex_file_field != nullptr);
483  if (dex_path_list == nullptr) {
484    // This may be null if the current class loader is under construction and it does not
485    // have its fields setup yet.
486    return true;
487  }
488  // DexPathList has an array dexElements of Elements[] which each contain a dex file.
489  ObjPtr<mirror::Object> dex_elements_obj =
490      jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)->
491          GetObject(dex_path_list);
492  // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look
493  // at the mCookie which is a DexFile vector.
494  if (dex_elements_obj == nullptr) {
495    // TODO(calin): It's unclear if we should just assert here. For now be prepared for the worse
496    // and assume we have no elements.
497    return true;
498  } else {
499    StackHandleScope<1> hs(soa.Self());
500    Handle<mirror::ObjectArray<mirror::Object>> dex_elements(
501        hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()));
502    for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
503      mirror::Object* element = dex_elements->GetWithoutChecks(i);
504      if (element == nullptr) {
505        // Should never happen, log an error and break.
506        // TODO(calin): It's unclear if we should just assert here.
507        // This code was propagated to oat_file_manager from the class linker where it would
508        // throw a NPE. For now, return false which will mark this class loader as unsupported.
509        LOG(ERROR) << "Unexpected null in the dex element list";
510        return false;
511      }
512      ObjPtr<mirror::Object> dex_file = dex_file_field->GetObject(element);
513      if (!CollectDexFilesFromJavaDexFile(dex_file, cookie_field, out_dex_files)) {
514        return false;
515      }
516    }
517  }
518
519  return true;
520}
521
522static bool GetDexFilesFromDexElementsArray(
523    ScopedObjectAccessAlreadyRunnable& soa,
524    Handle<mirror::ObjectArray<mirror::Object>> dex_elements,
525    std::vector<const DexFile*>* out_dex_files) REQUIRES_SHARED(Locks::mutator_lock_) {
526  DCHECK(dex_elements != nullptr);
527
528  ArtField* const cookie_field =
529      jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
530  ArtField* const dex_file_field =
531      jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
532  ObjPtr<mirror::Class> const element_class = soa.Decode<mirror::Class>(
533      WellKnownClasses::dalvik_system_DexPathList__Element);
534  ObjPtr<mirror::Class> const dexfile_class = soa.Decode<mirror::Class>(
535      WellKnownClasses::dalvik_system_DexFile);
536
537  for (int32_t i = 0; i < dex_elements->GetLength(); ++i) {
538    mirror::Object* element = dex_elements->GetWithoutChecks(i);
539    // We can hit a null element here because this is invoked with a partially filled dex_elements
540    // array from DexPathList. DexPathList will open each dex sequentially, each time passing the
541    // list of dex files which were opened before.
542    if (element == nullptr) {
543      continue;
544    }
545
546    // We support this being dalvik.system.DexPathList$Element and dalvik.system.DexFile.
547    // TODO(calin): Code caried over oat_file_manager: supporting both classes seem to be
548    // a historical glitch. All the java code opens dex files using an array of Elements.
549    ObjPtr<mirror::Object> dex_file;
550    if (element_class == element->GetClass()) {
551      dex_file = dex_file_field->GetObject(element);
552    } else if (dexfile_class == element->GetClass()) {
553      dex_file = element;
554    } else {
555      LOG(ERROR) << "Unsupported element in dex_elements: "
556                 << mirror::Class::PrettyClass(element->GetClass());
557      return false;
558    }
559
560    if (!CollectDexFilesFromJavaDexFile(dex_file, cookie_field, out_dex_files)) {
561      return false;
562    }
563  }
564  return true;
565}
566
567// Adds the `class_loader` info to the `context`.
568// The dex file present in `dex_elements` array (if not null) will be added at the end of
569// the classpath.
570// This method is recursive (w.r.t. the class loader parent) and will stop once it reaches the
571// BootClassLoader. Note that the class loader chain is expected to be short.
572bool ClassLoaderContext::AddInfoToContextFromClassLoader(
573      ScopedObjectAccessAlreadyRunnable& soa,
574      Handle<mirror::ClassLoader> class_loader,
575      Handle<mirror::ObjectArray<mirror::Object>> dex_elements)
576    REQUIRES_SHARED(Locks::mutator_lock_) {
577  if (ClassLinker::IsBootClassLoader(soa, class_loader.Get())) {
578    // Nothing to do for the boot class loader as we don't add its dex files to the context.
579    return true;
580  }
581
582  ClassLoaderContext::ClassLoaderType type;
583  if (IsPathOrDexClassLoader(soa, class_loader)) {
584    type = kPathClassLoader;
585  } else if (IsDelegateLastClassLoader(soa, class_loader)) {
586    type = kDelegateLastClassLoader;
587  } else {
588    LOG(WARNING) << "Unsupported class loader";
589    return false;
590  }
591
592  // Inspect the class loader for its dex files.
593  std::vector<const DexFile*> dex_files_loaded;
594  CollectDexFilesFromSupportedClassLoader(soa, class_loader, &dex_files_loaded);
595
596  // If we have a dex_elements array extract its dex elements now.
597  // This is used in two situations:
598  //   1) when a new ClassLoader is created DexPathList will open each dex file sequentially
599  //      passing the list of already open dex files each time. This ensures that we see the
600  //      correct context even if the ClassLoader under construction is not fully build.
601  //   2) when apk splits are loaded on the fly, the framework will load their dex files by
602  //      appending them to the current class loader. When the new code paths are loaded in
603  //      BaseDexClassLoader, the paths already present in the class loader will be passed
604  //      in the dex_elements array.
605  if (dex_elements != nullptr) {
606    GetDexFilesFromDexElementsArray(soa, dex_elements, &dex_files_loaded);
607  }
608
609  class_loader_chain_.push_back(ClassLoaderContext::ClassLoaderInfo(type));
610  ClassLoaderInfo& info = class_loader_chain_.back();
611  for (const DexFile* dex_file : dex_files_loaded) {
612    info.classpath.push_back(dex_file->GetLocation());
613    info.checksums.push_back(dex_file->GetLocationChecksum());
614    info.opened_dex_files.emplace_back(dex_file);
615  }
616
617  // We created the ClassLoaderInfo for the current loader. Move on to its parent.
618
619  StackHandleScope<1> hs(Thread::Current());
620  Handle<mirror::ClassLoader> parent = hs.NewHandle(class_loader->GetParent());
621
622  // Note that dex_elements array is null here. The elements are considered to be part of the
623  // current class loader and are not passed to the parents.
624  ScopedNullHandle<mirror::ObjectArray<mirror::Object>> null_dex_elements;
625  return AddInfoToContextFromClassLoader(soa, parent, null_dex_elements);
626}
627
628std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoader(
629    jobject class_loader,
630    jobjectArray dex_elements) {
631  CHECK(class_loader != nullptr);
632
633  ScopedObjectAccess soa(Thread::Current());
634  StackHandleScope<2> hs(soa.Self());
635  Handle<mirror::ClassLoader> h_class_loader =
636      hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader));
637  Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
638      hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
639
640  std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext(/*owns_the_dex_files*/ false));
641  if (result->AddInfoToContextFromClassLoader(soa, h_class_loader, h_dex_elements)) {
642    return result;
643  } else {
644    return nullptr;
645  }
646}
647
648static bool IsAbsoluteLocation(const std::string& location) {
649  return !location.empty() && location[0] == '/';
650}
651
652bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) const {
653  DCHECK(dex_files_open_attempted_);
654  DCHECK(dex_files_open_result_);
655
656  ClassLoaderContext expected_context;
657  if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) {
658    LOG(WARNING) << "Invalid class loader context: " << context_spec;
659    return false;
660  }
661
662  // Special shared library contexts always match. They essentially instruct the runtime
663  // to ignore the class path check because the oat file is known to be loaded in different
664  // contexts. OatFileManager will further verify if the oat file can be loaded based on the
665  // collision check.
666  if (special_shared_library_ || expected_context.special_shared_library_) {
667    return true;
668  }
669
670  if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) {
671    LOG(WARNING) << "ClassLoaderContext size mismatch. expected="
672        << expected_context.class_loader_chain_.size()
673        << ", actual=" << class_loader_chain_.size()
674        << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
675    return false;
676  }
677
678  for (size_t i = 0; i < class_loader_chain_.size(); i++) {
679    const ClassLoaderInfo& info = class_loader_chain_[i];
680    const ClassLoaderInfo& expected_info = expected_context.class_loader_chain_[i];
681    if (info.type != expected_info.type) {
682      LOG(WARNING) << "ClassLoaderContext type mismatch for position " << i
683          << ". expected=" << GetClassLoaderTypeName(expected_info.type)
684          << ", found=" << GetClassLoaderTypeName(info.type)
685          << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
686      return false;
687    }
688    if (info.classpath.size() != expected_info.classpath.size()) {
689      LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i
690            << ". expected=" << expected_info.classpath.size()
691            << ", found=" << info.classpath.size()
692            << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
693      return false;
694    }
695
696    DCHECK_EQ(info.classpath.size(), info.checksums.size());
697    DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
698
699    for (size_t k = 0; k < info.classpath.size(); k++) {
700      // Compute the dex location that must be compared.
701      // We shouldn't do a naive comparison `info.classpath[k] == expected_info.classpath[k]`
702      // because even if they refer to the same file, one could be encoded as a relative location
703      // and the other as an absolute one.
704      bool is_dex_name_absolute = IsAbsoluteLocation(info.classpath[k]);
705      bool is_expected_dex_name_absolute = IsAbsoluteLocation(expected_info.classpath[k]);
706      std::string dex_name;
707      std::string expected_dex_name;
708
709      if (is_dex_name_absolute == is_expected_dex_name_absolute) {
710        // If both locations are absolute or relative then compare them as they are.
711        // This is usually the case for: shared libraries and secondary dex files.
712        dex_name = info.classpath[k];
713        expected_dex_name = expected_info.classpath[k];
714      } else if (is_dex_name_absolute) {
715        // The runtime name is absolute but the compiled name (the expected one) is relative.
716        // This is the case for split apks which depend on base or on other splits.
717        dex_name = info.classpath[k];
718        expected_dex_name = OatFile::ResolveRelativeEncodedDexLocation(
719            info.classpath[k].c_str(), expected_info.classpath[k]);
720      } else if (is_expected_dex_name_absolute) {
721        // The runtime name is relative but the compiled name is absolute.
722        // There is no expected use case that would end up here as dex files are always loaded
723        // with their absolute location. However, be tolerant and do the best effort (in case
724        // there are unexpected new use case...).
725        dex_name = OatFile::ResolveRelativeEncodedDexLocation(
726            expected_info.classpath[k].c_str(), info.classpath[k]);
727        expected_dex_name = expected_info.classpath[k];
728      } else {
729        // Both locations are relative. In this case there's not much we can be sure about
730        // except that the names are the same. The checksum will ensure that the files are
731        // are same. This should not happen outside testing and manual invocations.
732        dex_name = info.classpath[k];
733        expected_dex_name = expected_info.classpath[k];
734      }
735
736      // Compare the locations.
737      if (dex_name != expected_dex_name) {
738        LOG(WARNING) << "ClassLoaderContext classpath element mismatch for position " << i
739            << ". expected=" << expected_info.classpath[k]
740            << ", found=" << info.classpath[k]
741            << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
742        return false;
743      }
744
745      // Compare the checksums.
746      if (info.checksums[k] != expected_info.checksums[k]) {
747        LOG(WARNING) << "ClassLoaderContext classpath element checksum mismatch for position " << i
748                     << ". expected=" << expected_info.checksums[k]
749                     << ", found=" << info.checksums[k]
750                     << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
751        return false;
752      }
753    }
754  }
755  return true;
756}
757
758jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) {
759  switch (type) {
760    case kPathClassLoader: return WellKnownClasses::dalvik_system_PathClassLoader;
761    case kDelegateLastClassLoader: return WellKnownClasses::dalvik_system_DelegateLastClassLoader;
762    case kInvalidClassLoader: break;  // will fail after the switch.
763  }
764  LOG(FATAL) << "Invalid class loader type " << type;
765  UNREACHABLE();
766}
767
768}  // namespace art
769
770