xref: /aosp_15_r20/art/profman/boot_image_profile.cc (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 #include "boot_image_profile.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <memory>
20*795d594fSAndroid Build Coastguard Worker #include <set>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "android-base/file.h"
23*795d594fSAndroid Build Coastguard Worker #include "dex/class_accessor-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "dex/descriptors_names.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "dex/method_reference.h"
27*795d594fSAndroid Build Coastguard Worker #include "dex/type_reference.h"
28*795d594fSAndroid Build Coastguard Worker #include "profile/profile_compilation_info.h"
29*795d594fSAndroid Build Coastguard Worker #include "inline_cache_format_util.h"
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker namespace art {
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker using Hotness = ProfileCompilationInfo::MethodHotness;
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker static const std::string kMethodSep = "->";  // NOLINT [runtime/string] [4]
36*795d594fSAndroid Build Coastguard Worker static const std::string kPackageUseDelim = "@";  // NOLINT [runtime/string] [4]
37*795d594fSAndroid Build Coastguard Worker static constexpr char kMethodFlagStringHot = 'H';
38*795d594fSAndroid Build Coastguard Worker static constexpr char kMethodFlagStringStartup = 'S';
39*795d594fSAndroid Build Coastguard Worker static constexpr char kMethodFlagStringPostStartup = 'P';
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker // Returns the type descriptor of the given reference.
GetTypeDescriptor(const TypeReference & ref)42*795d594fSAndroid Build Coastguard Worker static std::string GetTypeDescriptor(const TypeReference& ref) {
43*795d594fSAndroid Build Coastguard Worker   const dex::TypeId& type_id = ref.dex_file->GetTypeId(ref.TypeIndex());
44*795d594fSAndroid Build Coastguard Worker   return ref.dex_file->GetTypeDescriptor(type_id);
45*795d594fSAndroid Build Coastguard Worker }
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker // Returns the method representation used in the text format of the boot image profile.
BootImageRepresentation(const MethodReference & ref)48*795d594fSAndroid Build Coastguard Worker static std::string BootImageRepresentation(const MethodReference& ref) {
49*795d594fSAndroid Build Coastguard Worker   const DexFile* dex_file = ref.dex_file;
50*795d594fSAndroid Build Coastguard Worker   const dex::MethodId& id = ref.GetMethodId();
51*795d594fSAndroid Build Coastguard Worker   std::string signature_string(dex_file->GetMethodSignature(id).ToString());
52*795d594fSAndroid Build Coastguard Worker   std::string type_string(dex_file->GetTypeDescriptor(dex_file->GetTypeId(id.class_idx_)));
53*795d594fSAndroid Build Coastguard Worker   std::string method_name(dex_file->GetMethodName(id));
54*795d594fSAndroid Build Coastguard Worker   return type_string +
55*795d594fSAndroid Build Coastguard Worker         kMethodSep +
56*795d594fSAndroid Build Coastguard Worker         method_name +
57*795d594fSAndroid Build Coastguard Worker         signature_string;
58*795d594fSAndroid Build Coastguard Worker }
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker // Returns the class representation used in the text format of the boot image profile.
BootImageRepresentation(const TypeReference & ref)61*795d594fSAndroid Build Coastguard Worker static std::string BootImageRepresentation(const TypeReference& ref) {
62*795d594fSAndroid Build Coastguard Worker   return GetTypeDescriptor(ref);
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker // Returns the class representation used in preloaded classes.
PreloadedClassesRepresentation(const TypeReference & ref)66*795d594fSAndroid Build Coastguard Worker static std::string PreloadedClassesRepresentation(const TypeReference& ref) {
67*795d594fSAndroid Build Coastguard Worker   std::string descriptor = GetTypeDescriptor(ref);
68*795d594fSAndroid Build Coastguard Worker   return DescriptorToDot(descriptor.c_str());
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker // Formats the list of packages from the item metadata as a debug string.
GetPackageUseString(const FlattenProfileData::ItemMetadata & metadata)72*795d594fSAndroid Build Coastguard Worker static std::string GetPackageUseString(const FlattenProfileData::ItemMetadata& metadata) {
73*795d594fSAndroid Build Coastguard Worker   std::string result;
74*795d594fSAndroid Build Coastguard Worker   for (const auto& it : metadata.GetAnnotations()) {
75*795d594fSAndroid Build Coastguard Worker     result += it.GetOriginPackageName() + ",";
76*795d594fSAndroid Build Coastguard Worker   }
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker   return metadata.GetAnnotations().empty()
79*795d594fSAndroid Build Coastguard Worker       ? result
80*795d594fSAndroid Build Coastguard Worker       : result.substr(0, result.size() - 1);
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker // Converts a method representation to its final profile format.
MethodToProfileFormat(const std::string & method,const FlattenProfileData::ItemMetadata & metadata,bool output_package_use)84*795d594fSAndroid Build Coastguard Worker static std::string MethodToProfileFormat(
85*795d594fSAndroid Build Coastguard Worker     const std::string& method,
86*795d594fSAndroid Build Coastguard Worker     const FlattenProfileData::ItemMetadata& metadata,
87*795d594fSAndroid Build Coastguard Worker     bool output_package_use) {
88*795d594fSAndroid Build Coastguard Worker   std::string flags_string;
89*795d594fSAndroid Build Coastguard Worker   if (metadata.HasFlagSet(Hotness::kFlagHot)) {
90*795d594fSAndroid Build Coastguard Worker     flags_string += kMethodFlagStringHot;
91*795d594fSAndroid Build Coastguard Worker   }
92*795d594fSAndroid Build Coastguard Worker   if (metadata.HasFlagSet(Hotness::kFlagStartup)) {
93*795d594fSAndroid Build Coastguard Worker     flags_string += kMethodFlagStringStartup;
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker   if (metadata.HasFlagSet(Hotness::kFlagPostStartup)) {
96*795d594fSAndroid Build Coastguard Worker     flags_string += kMethodFlagStringPostStartup;
97*795d594fSAndroid Build Coastguard Worker   }
98*795d594fSAndroid Build Coastguard Worker   std::string extra;
99*795d594fSAndroid Build Coastguard Worker   if (output_package_use) {
100*795d594fSAndroid Build Coastguard Worker     extra = kPackageUseDelim + GetPackageUseString(metadata);
101*795d594fSAndroid Build Coastguard Worker   }
102*795d594fSAndroid Build Coastguard Worker 
103*795d594fSAndroid Build Coastguard Worker   std::string inline_cache_string = GetInlineCacheLine(metadata.GetInlineCache());
104*795d594fSAndroid Build Coastguard Worker   return flags_string + method + extra + inline_cache_string;
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker // Converts a class representation to its final profile or preloaded classes format.
ClassToProfileFormat(const std::string & classString,const FlattenProfileData::ItemMetadata & metadata,bool output_package_use)108*795d594fSAndroid Build Coastguard Worker static std::string ClassToProfileFormat(
109*795d594fSAndroid Build Coastguard Worker     const std::string& classString,
110*795d594fSAndroid Build Coastguard Worker     const FlattenProfileData::ItemMetadata& metadata,
111*795d594fSAndroid Build Coastguard Worker     bool output_package_use) {
112*795d594fSAndroid Build Coastguard Worker   std::string extra;
113*795d594fSAndroid Build Coastguard Worker   if (output_package_use) {
114*795d594fSAndroid Build Coastguard Worker     extra = kPackageUseDelim + GetPackageUseString(metadata);
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker   return classString + extra;
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker // Tries to asses if the given type reference is a clean class.
MaybeIsClassClean(const TypeReference & ref)121*795d594fSAndroid Build Coastguard Worker static bool MaybeIsClassClean(const TypeReference& ref) {
122*795d594fSAndroid Build Coastguard Worker   const dex::ClassDef* class_def = ref.dex_file->FindClassDef(ref.TypeIndex());
123*795d594fSAndroid Build Coastguard Worker   if (class_def == nullptr) {
124*795d594fSAndroid Build Coastguard Worker     return false;
125*795d594fSAndroid Build Coastguard Worker   }
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   ClassAccessor accessor(*ref.dex_file, *class_def);
128*795d594fSAndroid Build Coastguard Worker   for (auto& it : accessor.GetStaticFields()) {
129*795d594fSAndroid Build Coastguard Worker     if (!it.IsFinal()) {
130*795d594fSAndroid Build Coastguard Worker       // Not final static field will probably dirty the class.
131*795d594fSAndroid Build Coastguard Worker       return false;
132*795d594fSAndroid Build Coastguard Worker     }
133*795d594fSAndroid Build Coastguard Worker   }
134*795d594fSAndroid Build Coastguard Worker   for (auto& it : accessor.GetMethods()) {
135*795d594fSAndroid Build Coastguard Worker     uint32_t flags = it.GetAccessFlags();
136*795d594fSAndroid Build Coastguard Worker     if ((flags & kAccNative) != 0) {
137*795d594fSAndroid Build Coastguard Worker       // Native method will get dirtied.
138*795d594fSAndroid Build Coastguard Worker       return false;
139*795d594fSAndroid Build Coastguard Worker     }
140*795d594fSAndroid Build Coastguard Worker     if ((flags & kAccConstructor) != 0 && (flags & kAccStatic) != 0) {
141*795d594fSAndroid Build Coastguard Worker       // Class initializer, may get dirtied (not sure).
142*795d594fSAndroid Build Coastguard Worker       return false;
143*795d594fSAndroid Build Coastguard Worker     }
144*795d594fSAndroid Build Coastguard Worker   }
145*795d594fSAndroid Build Coastguard Worker 
146*795d594fSAndroid Build Coastguard Worker   return true;
147*795d594fSAndroid Build Coastguard Worker }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker // Returns true iff the item should be included in the profile.
150*795d594fSAndroid Build Coastguard Worker // (i.e. it passes the given aggregation thresholds)
IncludeItemInProfile(uint32_t max_aggregation_count,uint32_t item_threshold,const FlattenProfileData::ItemMetadata & metadata,const BootImageOptions & options)151*795d594fSAndroid Build Coastguard Worker static bool IncludeItemInProfile(uint32_t max_aggregation_count,
152*795d594fSAndroid Build Coastguard Worker                                  uint32_t item_threshold,
153*795d594fSAndroid Build Coastguard Worker                                  const FlattenProfileData::ItemMetadata& metadata,
154*795d594fSAndroid Build Coastguard Worker                                  const BootImageOptions& options) {
155*795d594fSAndroid Build Coastguard Worker   CHECK_NE(max_aggregation_count, 0u);
156*795d594fSAndroid Build Coastguard Worker   float item_percent = metadata.GetAnnotations().size() / static_cast<float>(max_aggregation_count);
157*795d594fSAndroid Build Coastguard Worker   for (const auto& annotIt : metadata.GetAnnotations()) {
158*795d594fSAndroid Build Coastguard Worker     const auto&thresholdIt =
159*795d594fSAndroid Build Coastguard Worker         options.special_packages_thresholds.find(annotIt.GetOriginPackageName());
160*795d594fSAndroid Build Coastguard Worker     if (thresholdIt != options.special_packages_thresholds.end()) {
161*795d594fSAndroid Build Coastguard Worker       if (item_percent >= (thresholdIt->second / 100.f)) {
162*795d594fSAndroid Build Coastguard Worker         return true;
163*795d594fSAndroid Build Coastguard Worker       }
164*795d594fSAndroid Build Coastguard Worker     }
165*795d594fSAndroid Build Coastguard Worker   }
166*795d594fSAndroid Build Coastguard Worker   return item_percent >= (item_threshold / 100.f);
167*795d594fSAndroid Build Coastguard Worker }
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker // Returns true iff a method with the given metada should be included in the profile.
IncludeMethodInProfile(uint32_t max_aggregation_count,const FlattenProfileData::ItemMetadata & metadata,const BootImageOptions & options)170*795d594fSAndroid Build Coastguard Worker static bool IncludeMethodInProfile(uint32_t max_aggregation_count,
171*795d594fSAndroid Build Coastguard Worker                                    const FlattenProfileData::ItemMetadata& metadata,
172*795d594fSAndroid Build Coastguard Worker                                    const BootImageOptions& options) {
173*795d594fSAndroid Build Coastguard Worker   return IncludeItemInProfile(max_aggregation_count, options.method_threshold, metadata, options);
174*795d594fSAndroid Build Coastguard Worker }
175*795d594fSAndroid Build Coastguard Worker 
176*795d594fSAndroid Build Coastguard Worker // Returns true iff a class with the given metada should be included in the profile.
IncludeClassInProfile(const TypeReference & type_ref,uint32_t max_aggregation_count,const FlattenProfileData::ItemMetadata & metadata,const BootImageOptions & options)177*795d594fSAndroid Build Coastguard Worker static bool IncludeClassInProfile(const TypeReference& type_ref,
178*795d594fSAndroid Build Coastguard Worker                                   uint32_t max_aggregation_count,
179*795d594fSAndroid Build Coastguard Worker                                   const FlattenProfileData::ItemMetadata& metadata,
180*795d594fSAndroid Build Coastguard Worker                                   const BootImageOptions& options) {
181*795d594fSAndroid Build Coastguard Worker   uint32_t threshold = MaybeIsClassClean(type_ref)
182*795d594fSAndroid Build Coastguard Worker       ? options.image_class_clean_threshold
183*795d594fSAndroid Build Coastguard Worker       : options.image_class_threshold;
184*795d594fSAndroid Build Coastguard Worker   return IncludeItemInProfile(max_aggregation_count, threshold, metadata, options);
185*795d594fSAndroid Build Coastguard Worker }
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker // Returns true iff a class with the given metada should be included in the list of
188*795d594fSAndroid Build Coastguard Worker // prelaoded classes.
IncludeInPreloadedClasses(const std::string & class_name,uint32_t max_aggregation_count,const FlattenProfileData::ItemMetadata & metadata,const BootImageOptions & options)189*795d594fSAndroid Build Coastguard Worker static bool IncludeInPreloadedClasses(const std::string& class_name,
190*795d594fSAndroid Build Coastguard Worker                                       uint32_t max_aggregation_count,
191*795d594fSAndroid Build Coastguard Worker                                       const FlattenProfileData::ItemMetadata& metadata,
192*795d594fSAndroid Build Coastguard Worker                                       const BootImageOptions& options) {
193*795d594fSAndroid Build Coastguard Worker   bool denylisted = options.preloaded_classes_denylist.find(class_name) !=
194*795d594fSAndroid Build Coastguard Worker       options.preloaded_classes_denylist.end();
195*795d594fSAndroid Build Coastguard Worker   return !denylisted && IncludeItemInProfile(
196*795d594fSAndroid Build Coastguard Worker       max_aggregation_count, options.preloaded_class_threshold, metadata, options);
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker 
GenerateBootImageProfile(const std::vector<std::unique_ptr<const DexFile>> & dex_files,const std::vector<std::string> & profile_files,const BootImageOptions & options,const std::string & boot_profile_out_path,const std::string & preloaded_classes_out_path)199*795d594fSAndroid Build Coastguard Worker bool GenerateBootImageProfile(
200*795d594fSAndroid Build Coastguard Worker     const std::vector<std::unique_ptr<const DexFile>>& dex_files,
201*795d594fSAndroid Build Coastguard Worker     const std::vector<std::string>& profile_files,
202*795d594fSAndroid Build Coastguard Worker     const BootImageOptions& options,
203*795d594fSAndroid Build Coastguard Worker     const std::string& boot_profile_out_path,
204*795d594fSAndroid Build Coastguard Worker     const std::string& preloaded_classes_out_path) {
205*795d594fSAndroid Build Coastguard Worker   if (boot_profile_out_path.empty()) {
206*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "No output file specified";
207*795d594fSAndroid Build Coastguard Worker     return false;
208*795d594fSAndroid Build Coastguard Worker   }
209*795d594fSAndroid Build Coastguard Worker 
210*795d594fSAndroid Build Coastguard Worker   bool generate_preloaded_classes = !preloaded_classes_out_path.empty();
211*795d594fSAndroid Build Coastguard Worker 
212*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<FlattenProfileData> flattend_data(new FlattenProfileData());
213*795d594fSAndroid Build Coastguard Worker   for (const std::string& profile_file : profile_files) {
214*795d594fSAndroid Build Coastguard Worker     ProfileCompilationInfo profile(/*for_boot_image=*/ true);
215*795d594fSAndroid Build Coastguard Worker     if (!profile.Load(profile_file, /*clear_if_invalid=*/ false)) {
216*795d594fSAndroid Build Coastguard Worker       LOG(ERROR) << "Profile is not a valid: " << profile_file;
217*795d594fSAndroid Build Coastguard Worker       return false;
218*795d594fSAndroid Build Coastguard Worker     }
219*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<FlattenProfileData> currentData = profile.ExtractProfileData(dex_files);
220*795d594fSAndroid Build Coastguard Worker     flattend_data->MergeData(*currentData);
221*795d594fSAndroid Build Coastguard Worker   }
222*795d594fSAndroid Build Coastguard Worker 
223*795d594fSAndroid Build Coastguard Worker   // We want the output sorted by the method/class name.
224*795d594fSAndroid Build Coastguard Worker   // So we use an intermediate map for that.
225*795d594fSAndroid Build Coastguard Worker   // There's no attempt to optimize this as it's not part of any critical path,
226*795d594fSAndroid Build Coastguard Worker   // and mostly executed on hosts.
227*795d594fSAndroid Build Coastguard Worker   SafeMap<std::string, FlattenProfileData::ItemMetadata> profile_methods;
228*795d594fSAndroid Build Coastguard Worker   SafeMap<std::string, FlattenProfileData::ItemMetadata> profile_classes;
229*795d594fSAndroid Build Coastguard Worker   SafeMap<std::string, FlattenProfileData::ItemMetadata> preloaded_classes;
230*795d594fSAndroid Build Coastguard Worker 
231*795d594fSAndroid Build Coastguard Worker   for (const auto& it : flattend_data->GetMethodData()) {
232*795d594fSAndroid Build Coastguard Worker     if (IncludeMethodInProfile(flattend_data->GetMaxAggregationForMethods(), it.second, options)) {
233*795d594fSAndroid Build Coastguard Worker       FlattenProfileData::ItemMetadata metadata(it.second);
234*795d594fSAndroid Build Coastguard Worker       if (options.upgrade_startup_to_hot
235*795d594fSAndroid Build Coastguard Worker           && ((metadata.GetFlags() & Hotness::Flag::kFlagStartup) != 0)) {
236*795d594fSAndroid Build Coastguard Worker         metadata.AddFlag(Hotness::Flag::kFlagHot);
237*795d594fSAndroid Build Coastguard Worker       }
238*795d594fSAndroid Build Coastguard Worker       profile_methods.Put(BootImageRepresentation(it.first), metadata);
239*795d594fSAndroid Build Coastguard Worker     }
240*795d594fSAndroid Build Coastguard Worker   }
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker   for (const auto& it : flattend_data->GetClassData()) {
243*795d594fSAndroid Build Coastguard Worker     const TypeReference& type_ref = it.first;
244*795d594fSAndroid Build Coastguard Worker     const FlattenProfileData::ItemMetadata& metadata = it.second;
245*795d594fSAndroid Build Coastguard Worker     if (IncludeClassInProfile(type_ref,
246*795d594fSAndroid Build Coastguard Worker             flattend_data->GetMaxAggregationForClasses(),
247*795d594fSAndroid Build Coastguard Worker             metadata,
248*795d594fSAndroid Build Coastguard Worker             options)) {
249*795d594fSAndroid Build Coastguard Worker       profile_classes.Put(BootImageRepresentation(it.first), it.second);
250*795d594fSAndroid Build Coastguard Worker     }
251*795d594fSAndroid Build Coastguard Worker     std::string preloaded_class_representation = PreloadedClassesRepresentation(it.first);
252*795d594fSAndroid Build Coastguard Worker     if (generate_preloaded_classes && IncludeInPreloadedClasses(
253*795d594fSAndroid Build Coastguard Worker             preloaded_class_representation,
254*795d594fSAndroid Build Coastguard Worker             flattend_data->GetMaxAggregationForClasses(),
255*795d594fSAndroid Build Coastguard Worker             metadata,
256*795d594fSAndroid Build Coastguard Worker             options)) {
257*795d594fSAndroid Build Coastguard Worker       preloaded_classes.Put(preloaded_class_representation, it.second);
258*795d594fSAndroid Build Coastguard Worker     }
259*795d594fSAndroid Build Coastguard Worker   }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker   // Create the output content
262*795d594fSAndroid Build Coastguard Worker   std::string profile_content;
263*795d594fSAndroid Build Coastguard Worker   std::string preloaded_content;
264*795d594fSAndroid Build Coastguard Worker   for (const auto& it : profile_classes) {
265*795d594fSAndroid Build Coastguard Worker     profile_content += ClassToProfileFormat(it.first, it.second, options.append_package_use_list)
266*795d594fSAndroid Build Coastguard Worker         + "\n";
267*795d594fSAndroid Build Coastguard Worker   }
268*795d594fSAndroid Build Coastguard Worker   for (const auto& it : profile_methods) {
269*795d594fSAndroid Build Coastguard Worker     profile_content += MethodToProfileFormat(it.first, it.second, options.append_package_use_list)
270*795d594fSAndroid Build Coastguard Worker         + "\n";
271*795d594fSAndroid Build Coastguard Worker   }
272*795d594fSAndroid Build Coastguard Worker 
273*795d594fSAndroid Build Coastguard Worker   if (generate_preloaded_classes) {
274*795d594fSAndroid Build Coastguard Worker     for (const auto& it : preloaded_classes) {
275*795d594fSAndroid Build Coastguard Worker       preloaded_content +=
276*795d594fSAndroid Build Coastguard Worker           ClassToProfileFormat(it.first, it.second, options.append_package_use_list) + "\n";
277*795d594fSAndroid Build Coastguard Worker     }
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker 
280*795d594fSAndroid Build Coastguard Worker   return android::base::WriteStringToFile(profile_content, boot_profile_out_path)
281*795d594fSAndroid Build Coastguard Worker       && (!generate_preloaded_classes
282*795d594fSAndroid Build Coastguard Worker           || android::base::WriteStringToFile(preloaded_content, preloaded_classes_out_path));
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker 
285*795d594fSAndroid Build Coastguard Worker }  // namespace art
286