Don't assume that the profile exists.
Before this change, the profile of a primary dex is created by
Package Manager on app installation, the profile of a secondary dex is
created by DexLoadReporter on dex load, and the runtime assumes that the
profile always exists. After this change, the runtime can create the
profile if it doesn't exist. This has the following benefits:
- When ART Services wants to clear a profile, it can simply delete it,
as opposed to the installd's approach: acquiring a flock and trucating
the file. This reduces the risk of artd encountering a dead lock.
- We can eventually make PM and DexLoadReporter simpler by removing the
code that creates profiles.
Bug: 248318911
Test: art/test.py -b -r --host -t 595
Ignore-AOSP-First: An internal-only change depends on it. Will
cherry-pick later.
Change-Id: I929e3856f02f498ed203d1af0e7859337a82669a
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index cea654f..cd2860b 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -23,7 +23,6 @@
#include <unistd.h>
#include "android-base/strings.h"
-
#include "art_method-inl.h"
#include "base/compiler_filter.h"
#include "base/enums.h"
@@ -32,6 +31,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/time_utils.h"
+#include "base/unix_file/fd_file.h"
#include "class_table-inl.h"
#include "dex/dex_file_loader.h"
#include "dex_reference_collection.h"
@@ -870,10 +870,23 @@
{
ProfileCompilationInfo info(Runtime::Current()->GetArenaPool(),
/*for_boot_image=*/ options_.GetProfileBootClassPath());
- if (!info.Load(filename, /*clear_if_invalid=*/ true)) {
- LOG(WARNING) << "Could not forcefully load profile " << filename;
- continue;
+ if (OS::FileExists(filename.c_str())) {
+ if (!info.Load(filename, /*clear_if_invalid=*/true)) {
+ LOG(WARNING) << "Could not forcefully load profile " << filename;
+ continue;
+ }
+ } else {
+ // Create a file if it doesn't exist.
+ unix_file::FdFile file(filename.c_str(),
+ O_WRONLY | O_TRUNC | O_CREAT,
+ S_IRUSR | S_IWUSR,
+ /*check_usage=*/false);
+ if (!file.IsValid()) {
+ LOG(WARNING) << "Could not create profile " << filename;
+ continue;
+ }
}
+
uint64_t last_save_number_of_methods = info.GetNumberOfMethods();
uint64_t last_save_number_of_classes = info.GetNumberOfResolvedClasses();
VLOG(profiler) << "last_save_number_of_methods=" << last_save_number_of_methods
diff --git a/test/595-profile-saving/src/Main.java b/test/595-profile-saving/src/Main.java
index 5b1a448..37a8e6c 100644
--- a/test/595-profile-saving/src/Main.java
+++ b/test/595-profile-saving/src/Main.java
@@ -39,8 +39,12 @@
File.class, Method.class);
testAddMethodToProfile(file, appMethod);
+ // Delete the file to check that the runtime can save the profile even if the file doesn't
+ // exist.
+ file.delete();
+
// Test that the profile saves a boot class path method with a profiling info.
- Method bootMethod = File.class.getDeclaredMethod("delete");
+ Method bootMethod = File.class.getDeclaredMethod("exists");
if (bootMethod.getDeclaringClass().getClassLoader() != Object.class.getClassLoader()) {
System.out.println("Class loader does not match boot class");
}