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