Home | History | Annotate | Download | only in jit
      1 /*
      2  * Copyright (C) 2015 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 "profile_saver.h"
     18 
     19 #include <sys/types.h>
     20 #include <sys/stat.h>
     21 #include <fcntl.h>
     22 
     23 #include "art_method-inl.h"
     24 #include "base/systrace.h"
     25 #include "base/time_utils.h"
     26 #include "compiler_filter.h"
     27 #include "oat_file_manager.h"
     28 #include "scoped_thread_state_change.h"
     29 
     30 
     31 namespace art {
     32 
     33 // TODO: read the constants from ProfileOptions,
     34 // Add a random delay each time we go to sleep so that we don't hammer the CPU
     35 // with all profile savers running at the same time.
     36 static constexpr const uint64_t kMinSavePeriodNs = MsToNs(20 * 1000);  // 20 seconds
     37 static constexpr const uint64_t kSaveResolvedClassesDelayMs = 2 * 1000;  // 2 seconds
     38 // Minimum number of JIT samples during launch to include a method into the profile.
     39 static constexpr const size_t kStartupMethodSamples = 1;
     40 
     41 static constexpr const uint32_t kMinimumNumberOfMethodsToSave = 10;
     42 static constexpr const uint32_t kMinimumNumberOfClassesToSave = 10;
     43 static constexpr const uint32_t kMinimumNumberOfNotificationBeforeWake =
     44     kMinimumNumberOfMethodsToSave;
     45 static constexpr const uint32_t kMaximumNumberOfNotificationBeforeWake = 50;
     46 
     47 
     48 ProfileSaver* ProfileSaver::instance_ = nullptr;
     49 pthread_t ProfileSaver::profiler_pthread_ = 0U;
     50 
     51 ProfileSaver::ProfileSaver(const std::string& output_filename,
     52                            jit::JitCodeCache* jit_code_cache,
     53                            const std::vector<std::string>& code_paths,
     54                            const std::string& foreign_dex_profile_path,
     55                            const std::string& app_data_dir)
     56     : jit_code_cache_(jit_code_cache),
     57       foreign_dex_profile_path_(foreign_dex_profile_path),
     58       shutting_down_(false),
     59       last_save_number_of_methods_(0),
     60       last_save_number_of_classes_(0),
     61       last_time_ns_saver_woke_up_(0),
     62       jit_activity_notifications_(0),
     63       wait_lock_("ProfileSaver wait lock"),
     64       period_condition_("ProfileSaver period condition", wait_lock_),
     65       total_bytes_written_(0),
     66       total_number_of_writes_(0),
     67       total_number_of_code_cache_queries_(0),
     68       total_number_of_skipped_writes_(0),
     69       total_number_of_failed_writes_(0),
     70       total_ms_of_sleep_(0),
     71       total_ns_of_work_(0),
     72       total_number_of_foreign_dex_marks_(0),
     73       max_number_of_profile_entries_cached_(0),
     74       total_number_of_hot_spikes_(0),
     75       total_number_of_wake_ups_(0) {
     76   AddTrackedLocations(output_filename, app_data_dir, code_paths);
     77 }
     78 
     79 void ProfileSaver::Run() {
     80   Thread* self = Thread::Current();
     81 
     82   // Fetch the resolved classes for the app images after sleeping for
     83   // kSaveResolvedClassesDelayMs.
     84   // TODO(calin) This only considers the case of the primary profile file.
     85   // Anything that gets loaded in the same VM will not have their resolved
     86   // classes save (unless they started before the initial saving was done).
     87   {
     88     MutexLock mu(self, wait_lock_);
     89     constexpr uint64_t kSleepTime = kSaveResolvedClassesDelayMs;
     90     const uint64_t end_time = NanoTime() + MsToNs(kSleepTime);
     91     while (true) {
     92       const uint64_t current_time = NanoTime();
     93       if (current_time >= end_time) {
     94         break;
     95       }
     96       period_condition_.TimedWait(self, NsToMs(end_time - current_time), 0);
     97     }
     98     total_ms_of_sleep_ += kSaveResolvedClassesDelayMs;
     99   }
    100   FetchAndCacheResolvedClassesAndMethods();
    101 
    102   // Loop for the profiled methods.
    103   while (!ShuttingDown(self)) {
    104     uint64_t sleep_start = NanoTime();
    105     {
    106       uint64_t sleep_time = 0;
    107       {
    108         MutexLock mu(self, wait_lock_);
    109         period_condition_.Wait(self);
    110         sleep_time = NanoTime() - sleep_start;
    111       }
    112       // Check if the thread was woken up for shutdown.
    113       if (ShuttingDown(self)) {
    114         break;
    115       }
    116       total_number_of_wake_ups_++;
    117       // We might have been woken up by a huge number of notifications to guarantee saving.
    118       // If we didn't meet the minimum saving period go back to sleep (only if missed by
    119       // a reasonable margin).
    120       while (kMinSavePeriodNs * 0.9 > sleep_time) {
    121         {
    122           MutexLock mu(self, wait_lock_);
    123           period_condition_.TimedWait(self, NsToMs(kMinSavePeriodNs - sleep_time), 0);
    124           sleep_time = NanoTime() - sleep_start;
    125         }
    126         // Check if the thread was woken up for shutdown.
    127         if (ShuttingDown(self)) {
    128           break;
    129         }
    130         total_number_of_wake_ups_++;
    131       }
    132     }
    133     total_ms_of_sleep_ += NsToMs(NanoTime() - sleep_start);
    134 
    135     if (ShuttingDown(self)) {
    136       break;
    137     }
    138 
    139     uint16_t new_methods = 0;
    140     uint64_t start_work = NanoTime();
    141     bool profile_saved_to_disk = ProcessProfilingInfo(&new_methods);
    142     // Update the notification counter based on result. Note that there might be contention on this
    143     // but we don't care about to be 100% precise.
    144     if (!profile_saved_to_disk) {
    145       // If we didn't save to disk it may be because we didn't have enough new methods.
    146       // Set the jit activity notifications to new_methods so we can wake up earlier if needed.
    147       jit_activity_notifications_ = new_methods;
    148     }
    149     total_ns_of_work_ += NanoTime() - start_work;
    150   }
    151 }
    152 
    153 void ProfileSaver::NotifyJitActivity() {
    154   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    155   if (instance_ == nullptr || instance_->shutting_down_) {
    156     return;
    157   }
    158   instance_->NotifyJitActivityInternal();
    159 }
    160 
    161 void ProfileSaver::WakeUpSaver() {
    162   jit_activity_notifications_ = 0;
    163   last_time_ns_saver_woke_up_ = NanoTime();
    164   period_condition_.Signal(Thread::Current());
    165 }
    166 
    167 void ProfileSaver::NotifyJitActivityInternal() {
    168   // Unlikely to overflow but if it happens,
    169   // we would have waken up the saver long before that.
    170   jit_activity_notifications_++;
    171   // Note that we are not as precise as we could be here but we don't want to wake the saver
    172   // every time we see a hot method.
    173   if (jit_activity_notifications_ > kMinimumNumberOfNotificationBeforeWake) {
    174     MutexLock wait_mutex(Thread::Current(), wait_lock_);
    175     if ((NanoTime() - last_time_ns_saver_woke_up_) > kMinSavePeriodNs) {
    176       WakeUpSaver();
    177     }
    178   } else if (jit_activity_notifications_ > kMaximumNumberOfNotificationBeforeWake) {
    179     // Make sure to wake up the saver if we see a spike in the number of notifications.
    180     // This is a precaution to avoid "loosing" a big number of methods in case
    181     // this is a spike with no jit after.
    182     total_number_of_hot_spikes_++;
    183     MutexLock wait_mutex(Thread::Current(), wait_lock_);
    184     WakeUpSaver();
    185   }
    186 }
    187 
    188 ProfileCompilationInfo* ProfileSaver::GetCachedProfiledInfo(const std::string& filename) {
    189   auto info_it = profile_cache_.find(filename);
    190   if (info_it == profile_cache_.end()) {
    191     info_it = profile_cache_.Put(filename, ProfileCompilationInfo());
    192   }
    193   return &info_it->second;
    194 }
    195 
    196 // Get resolved methods that have a profile info or more than kStartupMethodSamples samples.
    197 // Excludes native methods and classes in the boot image.
    198 class GetMethodsVisitor : public ClassVisitor {
    199  public:
    200   explicit GetMethodsVisitor(std::vector<MethodReference>* methods) : methods_(methods) {}
    201 
    202   virtual bool operator()(mirror::Class* klass) SHARED_REQUIRES(Locks::mutator_lock_) {
    203     if (Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
    204       return true;
    205     }
    206     for (ArtMethod& method : klass->GetMethods(sizeof(void*))) {
    207       if (!method.IsNative()) {
    208         if (method.GetCounter() >= kStartupMethodSamples ||
    209             method.GetProfilingInfo(sizeof(void*)) != nullptr) {
    210           // Have samples, add to profile.
    211           const DexFile* dex_file = method.GetInterfaceMethodIfProxy(sizeof(void*))->GetDexFile();
    212           methods_->push_back(MethodReference(dex_file, method.GetDexMethodIndex()));
    213         }
    214       }
    215     }
    216     return true;
    217   }
    218 
    219  private:
    220   std::vector<MethodReference>* const methods_;
    221 };
    222 
    223 void ProfileSaver::FetchAndCacheResolvedClassesAndMethods() {
    224   ScopedTrace trace(__PRETTY_FUNCTION__);
    225   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
    226   std::set<DexCacheResolvedClasses> resolved_classes =
    227       class_linker->GetResolvedClasses(/*ignore boot classes*/ true);
    228 
    229   std::vector<MethodReference> methods;
    230   {
    231     ScopedTrace trace2("Get hot methods");
    232     GetMethodsVisitor visitor(&methods);
    233     ScopedObjectAccess soa(Thread::Current());
    234     class_linker->VisitClasses(&visitor);
    235     VLOG(profiler) << "Methods with samples greater than "
    236                    << kStartupMethodSamples << " = " << methods.size();
    237   }
    238   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    239   uint64_t total_number_of_profile_entries_cached = 0;
    240 
    241   for (const auto& it : tracked_dex_base_locations_) {
    242     std::set<DexCacheResolvedClasses> resolved_classes_for_location;
    243     const std::string& filename = it.first;
    244     const std::set<std::string>& locations = it.second;
    245     std::vector<MethodReference> methods_for_location;
    246     for (const MethodReference& ref : methods) {
    247       if (locations.find(ref.dex_file->GetBaseLocation()) != locations.end()) {
    248         methods_for_location.push_back(ref);
    249       }
    250     }
    251     for (const DexCacheResolvedClasses& classes : resolved_classes) {
    252       if (locations.find(classes.GetBaseLocation()) != locations.end()) {
    253         VLOG(profiler) << "Added " << classes.GetClasses().size() << " classes for location "
    254                        << classes.GetBaseLocation() << " (" << classes.GetDexLocation() << ")";
    255         resolved_classes_for_location.insert(classes);
    256       } else {
    257         VLOG(profiler) << "Location not found " << classes.GetBaseLocation()
    258                        << " (" << classes.GetDexLocation() << ")";
    259       }
    260     }
    261     ProfileCompilationInfo* info = GetCachedProfiledInfo(filename);
    262     info->AddMethodsAndClasses(methods_for_location, resolved_classes_for_location);
    263     total_number_of_profile_entries_cached += resolved_classes_for_location.size();
    264   }
    265   max_number_of_profile_entries_cached_ = std::max(
    266       max_number_of_profile_entries_cached_,
    267       total_number_of_profile_entries_cached);
    268 }
    269 
    270 bool ProfileSaver::ProcessProfilingInfo(uint16_t* new_methods) {
    271   ScopedTrace trace(__PRETTY_FUNCTION__);
    272   SafeMap<std::string, std::set<std::string>> tracked_locations;
    273   {
    274     // Make a copy so that we don't hold the lock while doing I/O.
    275     MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    276     tracked_locations = tracked_dex_base_locations_;
    277   }
    278 
    279   bool profile_file_saved = false;
    280   uint64_t total_number_of_profile_entries_cached = 0;
    281   *new_methods = 0;
    282 
    283   for (const auto& it : tracked_locations) {
    284     if (ShuttingDown(Thread::Current())) {
    285       return true;
    286     }
    287     const std::string& filename = it.first;
    288     const std::set<std::string>& locations = it.second;
    289     std::vector<MethodReference> methods;
    290     {
    291       ScopedObjectAccess soa(Thread::Current());
    292       jit_code_cache_->GetProfiledMethods(locations, methods);
    293       total_number_of_code_cache_queries_++;
    294     }
    295 
    296     ProfileCompilationInfo* cached_info = GetCachedProfiledInfo(filename);
    297     cached_info->AddMethodsAndClasses(methods, std::set<DexCacheResolvedClasses>());
    298     int64_t delta_number_of_methods =
    299         cached_info->GetNumberOfMethods() -
    300         static_cast<int64_t>(last_save_number_of_methods_);
    301     int64_t delta_number_of_classes =
    302         cached_info->GetNumberOfResolvedClasses() -
    303         static_cast<int64_t>(last_save_number_of_classes_);
    304 
    305     if (delta_number_of_methods < kMinimumNumberOfMethodsToSave &&
    306         delta_number_of_classes < kMinimumNumberOfClassesToSave) {
    307       VLOG(profiler) << "Not enough information to save to: " << filename
    308           << " Nr of methods: " << delta_number_of_methods
    309           << " Nr of classes: " << delta_number_of_classes;
    310       total_number_of_skipped_writes_++;
    311       continue;
    312     }
    313     *new_methods = std::max(static_cast<uint16_t>(delta_number_of_methods), *new_methods);
    314     uint64_t bytes_written;
    315     // Force the save. In case the profile data is corrupted or the the profile
    316     // has the wrong version this will "fix" the file to the correct format.
    317     if (cached_info->MergeAndSave(filename, &bytes_written, /*force*/ true)) {
    318       last_save_number_of_methods_ = cached_info->GetNumberOfMethods();
    319       last_save_number_of_classes_ = cached_info->GetNumberOfResolvedClasses();
    320       // Clear resolved classes. No need to store them around as
    321       // they don't change after the first write.
    322       cached_info->ClearResolvedClasses();
    323       if (bytes_written > 0) {
    324         total_number_of_writes_++;
    325         total_bytes_written_ += bytes_written;
    326         profile_file_saved = true;
    327       } else {
    328         // At this point we could still have avoided the write.
    329         // We load and merge the data from the file lazily at its first ever
    330         // save attempt. So, whatever we are trying to save could already be
    331         // in the file.
    332         total_number_of_skipped_writes_++;
    333       }
    334     } else {
    335       LOG(WARNING) << "Could not save profiling info to " << filename;
    336       total_number_of_failed_writes_++;
    337     }
    338     total_number_of_profile_entries_cached +=
    339         cached_info->GetNumberOfMethods() +
    340         cached_info->GetNumberOfResolvedClasses();
    341   }
    342   max_number_of_profile_entries_cached_ = std::max(
    343       max_number_of_profile_entries_cached_,
    344       total_number_of_profile_entries_cached);
    345   return profile_file_saved;
    346 }
    347 
    348 void* ProfileSaver::RunProfileSaverThread(void* arg) {
    349   Runtime* runtime = Runtime::Current();
    350 
    351   bool attached = runtime->AttachCurrentThread("Profile Saver",
    352                                                /*as_daemon*/true,
    353                                                runtime->GetSystemThreadGroup(),
    354                                                /*create_peer*/true);
    355   if (!attached) {
    356     CHECK(runtime->IsShuttingDown(Thread::Current()));
    357     return nullptr;
    358   }
    359 
    360   ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg);
    361   profile_saver->Run();
    362 
    363   runtime->DetachCurrentThread();
    364   VLOG(profiler) << "Profile saver shutdown";
    365   return nullptr;
    366 }
    367 
    368 static bool ShouldProfileLocation(const std::string& location) {
    369   OatFileManager& oat_manager = Runtime::Current()->GetOatFileManager();
    370   const OatFile* oat_file = oat_manager.FindOpenedOatFileFromDexLocation(location);
    371   if (oat_file == nullptr) {
    372     // This can happen if we fallback to run code directly from the APK.
    373     // Profile it with the hope that the background dexopt will get us back into
    374     // a good state.
    375     VLOG(profiler) << "Asked to profile a location without an oat file:" << location;
    376     return true;
    377   }
    378   CompilerFilter::Filter filter = oat_file->GetCompilerFilter();
    379   if ((filter == CompilerFilter::kSpeed) || (filter == CompilerFilter::kEverything)) {
    380     VLOG(profiler)
    381         << "Skip profiling oat file because it's already speed|everything compiled: "
    382         << location << " oat location: " << oat_file->GetLocation();
    383     return false;
    384   }
    385   return true;
    386 }
    387 
    388 void ProfileSaver::Start(const std::string& output_filename,
    389                          jit::JitCodeCache* jit_code_cache,
    390                          const std::vector<std::string>& code_paths,
    391                          const std::string& foreign_dex_profile_path,
    392                          const std::string& app_data_dir) {
    393   DCHECK(Runtime::Current()->SaveProfileInfo());
    394   DCHECK(!output_filename.empty());
    395   DCHECK(jit_code_cache != nullptr);
    396 
    397   std::vector<std::string> code_paths_to_profile;
    398 
    399   for (const std::string& location : code_paths) {
    400     if (ShouldProfileLocation(location))  {
    401       code_paths_to_profile.push_back(location);
    402     }
    403   }
    404   if (code_paths_to_profile.empty()) {
    405     VLOG(profiler) << "No code paths should be profiled.";
    406     return;
    407   }
    408 
    409   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    410   if (instance_ != nullptr) {
    411     // If we already have an instance, make sure it uses the same jit_code_cache.
    412     // This may be called multiple times via Runtime::registerAppInfo (e.g. for
    413     // apps which share the same runtime).
    414     DCHECK_EQ(instance_->jit_code_cache_, jit_code_cache);
    415     // Add the code_paths to the tracked locations.
    416     instance_->AddTrackedLocations(output_filename, app_data_dir, code_paths_to_profile);
    417     return;
    418   }
    419 
    420   VLOG(profiler) << "Starting profile saver using output file: " << output_filename
    421       << ". Tracking: " << Join(code_paths_to_profile, ':');
    422 
    423   instance_ = new ProfileSaver(output_filename,
    424                                jit_code_cache,
    425                                code_paths_to_profile,
    426                                foreign_dex_profile_path,
    427                                app_data_dir);
    428 
    429   // Create a new thread which does the saving.
    430   CHECK_PTHREAD_CALL(
    431       pthread_create,
    432       (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
    433       "Profile saver thread");
    434 }
    435 
    436 void ProfileSaver::Stop(bool dump_info) {
    437   ProfileSaver* profile_saver = nullptr;
    438   pthread_t profiler_pthread = 0U;
    439 
    440   {
    441     MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
    442     VLOG(profiler) << "Stopping profile saver thread";
    443     profile_saver = instance_;
    444     profiler_pthread = profiler_pthread_;
    445     if (instance_ == nullptr) {
    446       DCHECK(false) << "Tried to stop a profile saver which was not started";
    447       return;
    448     }
    449     if (instance_->shutting_down_) {
    450       DCHECK(false) << "Tried to stop the profile saver twice";
    451       return;
    452     }
    453     instance_->shutting_down_ = true;
    454     if (dump_info) {
    455       instance_->DumpInfo(LOG(INFO));
    456     }
    457   }
    458 
    459   {
    460     // Wake up the saver thread if it is sleeping to allow for a clean exit.
    461     MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
    462     profile_saver->period_condition_.Signal(Thread::Current());
    463   }
    464 
    465   // Wait for the saver thread to stop.
    466   CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
    467 
    468   {
    469     MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
    470     instance_ = nullptr;
    471     profiler_pthread_ = 0U;
    472   }
    473   delete profile_saver;
    474 }
    475 
    476 bool ProfileSaver::ShuttingDown(Thread* self) {
    477   MutexLock mu(self, *Locks::profiler_lock_);
    478   return shutting_down_;
    479 }
    480 
    481 bool ProfileSaver::IsStarted() {
    482   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    483   return instance_ != nullptr;
    484 }
    485 
    486 void ProfileSaver::AddTrackedLocations(const std::string& output_filename,
    487                                        const std::string& app_data_dir,
    488                                        const std::vector<std::string>& code_paths) {
    489   auto it = tracked_dex_base_locations_.find(output_filename);
    490   if (it == tracked_dex_base_locations_.end()) {
    491     tracked_dex_base_locations_.Put(output_filename,
    492                                     std::set<std::string>(code_paths.begin(), code_paths.end()));
    493     if (!app_data_dir.empty()) {
    494       app_data_dirs_.insert(app_data_dir);
    495     }
    496   } else {
    497     it->second.insert(code_paths.begin(), code_paths.end());
    498   }
    499 }
    500 
    501 // TODO(calin): This may lead to several calls to realpath.
    502 // Consider moving the logic to the saver thread (i.e. when notified,
    503 // only cache the location, and then wake up the saver thread to do the
    504 // comparisons with the real file paths and to create the markers).
    505 void ProfileSaver::NotifyDexUse(const std::string& dex_location) {
    506   if (!ShouldProfileLocation(dex_location)) {
    507     return;
    508   }
    509   std::set<std::string> app_code_paths;
    510   std::string foreign_dex_profile_path;
    511   std::set<std::string> app_data_dirs;
    512   {
    513     MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    514     if (instance_ == nullptr) {
    515       return;
    516     }
    517     // Make a copy so that we don't hold the lock while doing I/O.
    518     for (const auto& it : instance_->tracked_dex_base_locations_) {
    519       app_code_paths.insert(it.second.begin(), it.second.end());
    520     }
    521     foreign_dex_profile_path = instance_->foreign_dex_profile_path_;
    522     app_data_dirs.insert(instance_->app_data_dirs_.begin(), instance_->app_data_dirs_.end());
    523   }
    524 
    525   bool mark_created = MaybeRecordDexUseInternal(dex_location,
    526                                                 app_code_paths,
    527                                                 foreign_dex_profile_path,
    528                                                 app_data_dirs);
    529   if (mark_created) {
    530     MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    531     if (instance_ != nullptr) {
    532       instance_->total_number_of_foreign_dex_marks_++;
    533     }
    534   }
    535 }
    536 
    537 static bool CheckContainsWithRealPath(const std::set<std::string>& paths_set,
    538                                       const std::string& path_to_check) {
    539   for (const auto& path : paths_set) {
    540     UniqueCPtr<const char[]> real_path(realpath(path.c_str(), nullptr));
    541     if (real_path == nullptr) {
    542       PLOG(WARNING) << "Could not get realpath for " << path;
    543       continue;
    544     }
    545     std::string real_path_str(real_path.get());
    546     if (real_path_str == path_to_check) {
    547       return true;
    548     }
    549   }
    550   return false;
    551 }
    552 
    553 // After the call, dex_location_real_path will contain the marker's name.
    554 static bool CreateForeignDexMarker(const std::string& foreign_dex_profile_path,
    555                                    /*in-out*/ std::string* dex_location_real_path) {
    556   // For foreign dex files we record a flag on disk. PackageManager will (potentially) take this
    557   // into account when deciding how to optimize the loaded dex file.
    558   // The expected flag name is the canonical path of the apk where '/' is substituted to '@'.
    559   // (it needs to be kept in sync with
    560   // frameworks/base/services/core/java/com/android/server/pm/PackageDexOptimizer.java)
    561   std::replace(dex_location_real_path->begin(), dex_location_real_path->end(), '/', '@');
    562   std::string flag_path = foreign_dex_profile_path + "/" + *dex_location_real_path;
    563   // We use O_RDONLY as the access mode because we must supply some access
    564   // mode, and there is no access mode that means 'create but do not read' the
    565   // file. We will not not actually read from the file.
    566   int fd = TEMP_FAILURE_RETRY(open(flag_path.c_str(),
    567         O_CREAT | O_RDONLY | O_EXCL | O_CLOEXEC | O_NOFOLLOW, 0));
    568   if (fd != -1) {
    569     if (close(fd) != 0) {
    570       PLOG(WARNING) << "Could not close file after flagging foreign dex use " << flag_path;
    571     }
    572     return true;
    573   } else {
    574     if (errno != EEXIST && errno != EACCES) {
    575       // Another app could have already created the file, and selinux may not
    576       // allow the read access to the file implied by the call to open.
    577       PLOG(WARNING) << "Could not create foreign dex use mark " << flag_path;
    578       return false;
    579     }
    580     return true;
    581   }
    582 }
    583 
    584 bool ProfileSaver::MaybeRecordDexUseInternal(
    585       const std::string& dex_location,
    586       const std::set<std::string>& app_code_paths,
    587       const std::string& foreign_dex_profile_path,
    588       const std::set<std::string>& app_data_dirs) {
    589   if (dex_location.empty()) {
    590     LOG(WARNING) << "Asked to record foreign dex use with an empty dex location.";
    591     return false;
    592   }
    593   if (foreign_dex_profile_path.empty()) {
    594     LOG(WARNING) << "Asked to record foreign dex use without a valid profile path ";
    595     return false;
    596   }
    597 
    598   if (app_code_paths.find(dex_location) != app_code_paths.end()) {
    599     // The dex location belongs to the application code paths. Nothing to record.
    600     return false;
    601   }
    602 
    603   if (app_data_dirs.find(dex_location) != app_data_dirs.end()) {
    604     // The dex location is under the application folder. Nothing to record.
    605     return false;
    606   }
    607 
    608   // Do another round of checks with the real paths.
    609   // Application directory could be a symlink (e.g. /data/data instead of /data/user/0), and we
    610   // don't have control over how the dex files are actually loaded (symlink or canonical path),
    611 
    612   // Note that we could cache all the real locations in the saver (since it's an expensive
    613   // operation). However we expect that app_code_paths is small (usually 1 element), and
    614   // NotifyDexUse is called just a few times in the app lifetime. So we make the compromise
    615   // to save some bytes of memory usage.
    616 
    617   UniqueCPtr<const char[]> dex_location_real_path(realpath(dex_location.c_str(), nullptr));
    618   if (dex_location_real_path == nullptr) {
    619     PLOG(WARNING) << "Could not get realpath for " << dex_location;
    620     return false;
    621   }
    622   std::string dex_location_real_path_str(dex_location_real_path.get());
    623 
    624   if (CheckContainsWithRealPath(app_code_paths, dex_location_real_path_str)) {
    625     return false;
    626   }
    627 
    628   if (CheckContainsWithRealPath(app_data_dirs, dex_location_real_path_str)) {
    629     return false;
    630   }
    631 
    632   return CreateForeignDexMarker(foreign_dex_profile_path, &dex_location_real_path_str);
    633 }
    634 
    635 void ProfileSaver::DumpInstanceInfo(std::ostream& os) {
    636   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    637   if (instance_ != nullptr) {
    638     instance_->DumpInfo(os);
    639   }
    640 }
    641 
    642 void ProfileSaver::DumpInfo(std::ostream& os) {
    643   os << "ProfileSaver total_bytes_written=" << total_bytes_written_ << '\n'
    644      << "ProfileSaver total_number_of_writes=" << total_number_of_writes_ << '\n'
    645      << "ProfileSaver total_number_of_code_cache_queries="
    646      << total_number_of_code_cache_queries_ << '\n'
    647      << "ProfileSaver total_number_of_skipped_writes=" << total_number_of_skipped_writes_ << '\n'
    648      << "ProfileSaver total_number_of_failed_writes=" << total_number_of_failed_writes_ << '\n'
    649      << "ProfileSaver total_ms_of_sleep=" << total_ms_of_sleep_ << '\n'
    650      << "ProfileSaver total_ms_of_work=" << NsToMs(total_ns_of_work_) << '\n'
    651      << "ProfileSaver total_number_of_foreign_dex_marks="
    652      << total_number_of_foreign_dex_marks_ << '\n'
    653      << "ProfileSaver max_number_profile_entries_cached="
    654      << max_number_of_profile_entries_cached_ << '\n'
    655      << "ProfileSaver total_number_of_hot_spikes=" << total_number_of_hot_spikes_ << '\n'
    656      << "ProfileSaver total_number_of_wake_ups=" << total_number_of_wake_ups_ << '\n';
    657 }
    658 
    659 
    660 void ProfileSaver::ForceProcessProfiles() {
    661   ProfileSaver* saver = nullptr;
    662   {
    663     MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    664     saver = instance_;
    665   }
    666   // TODO(calin): this is not actually thread safe as the instance_ may have been deleted,
    667   // but we only use this in testing when we now this won't happen.
    668   // Refactor the way we handle the instance so that we don't end up in this situation.
    669   if (saver != nullptr) {
    670     uint16_t new_methods;
    671     saver->ProcessProfilingInfo(&new_methods);
    672   }
    673 }
    674 
    675 bool ProfileSaver::HasSeenMethod(const std::string& profile,
    676                                  const DexFile* dex_file,
    677                                  uint16_t method_idx) {
    678   MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
    679   if (instance_ != nullptr) {
    680     ProfileCompilationInfo* info = instance_->GetCachedProfiledInfo(profile);
    681     if (info != nullptr) {
    682       return info->ContainsMethod(MethodReference(dex_file, method_idx));
    683     }
    684   }
    685   return false;
    686 }
    687 
    688 }   // namespace art
    689