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_compilation_info.h"
18 
19 #include <fcntl.h>
20 #include <sys/file.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <zlib.h>
25 
26 #include <algorithm>
27 #include <cerrno>
28 #include <climits>
29 #include <cstdio>
30 #include <cstdlib>
31 #include <iostream>
32 #include <numeric>
33 #include <random>
34 #include <string>
35 #include <unordered_map>
36 #include <unordered_set>
37 #include <vector>
38 
39 #include "android-base/file.h"
40 #include "android-base/properties.h"
41 #include "android-base/scopeguard.h"
42 #include "android-base/strings.h"
43 #include "android-base/unique_fd.h"
44 #include "base/arena_allocator.h"
45 #include "base/bit_utils.h"
46 #include "base/dumpable.h"
47 #include "base/file_utils.h"
48 #include "base/globals.h"
49 #include "base/logging.h"  // For VLOG.
50 #include "base/malloc_arena_pool.h"
51 #include "base/os.h"
52 #include "base/safe_map.h"
53 #include "base/scoped_flock.h"
54 #include "base/stl_util.h"
55 #include "base/systrace.h"
56 #include "base/time_utils.h"
57 #include "base/unix_file/fd_file.h"
58 #include "base/utils.h"
59 #include "base/zip_archive.h"
60 #include "dex/code_item_accessors-inl.h"
61 #include "dex/descriptors_names.h"
62 #include "dex/dex_file_loader.h"
63 
64 #ifdef ART_TARGET_ANDROID
65 #include "android-modules-utils/sdk_level.h"
66 #endif
67 
68 namespace art {
69 
70 const uint8_t ProfileCompilationInfo::kProfileMagic[] = { 'p', 'r', 'o', '\0' };
71 // Last profile version: New extensible profile format.
72 const uint8_t ProfileCompilationInfo::kProfileVersion[] = { '0', '1', '5', '\0' };
73 const uint8_t ProfileCompilationInfo::kProfileVersionForBootImage[] = { '0', '1', '6', '\0' };
74 
75 static_assert(sizeof(ProfileCompilationInfo::kProfileVersion) == 4,
76               "Invalid profile version size");
77 static_assert(sizeof(ProfileCompilationInfo::kProfileVersionForBootImage) == 4,
78               "Invalid profile version size");
79 
80 // The name of the profile entry in the dex metadata file.
81 // DO NOT CHANGE THIS! (it's similar to classes.dex in the apk files).
82 const char ProfileCompilationInfo::kDexMetadataProfileEntry[] = "primary.prof";
83 
84 // A synthetic annotations that can be used to denote that no annotation should
85 // be associated with the profile samples. We use the empty string for the package name
86 // because that's an invalid package name and should never occur in practice.
87 const ProfileCompilationInfo::ProfileSampleAnnotation
88   ProfileCompilationInfo::ProfileSampleAnnotation::kNone =
89       ProfileCompilationInfo::ProfileSampleAnnotation("");
90 
91 static constexpr char kSampleMetadataSeparator = ':';
92 
93 // Note: This used to be PATH_MAX (usually 4096) but that seems excessive
94 // and we do not want to rely on that external constant anyway.
95 static constexpr uint16_t kMaxDexFileKeyLength = 1024;
96 
97 // Extra descriptors are serialized with a `uint16_t` prefix. This defines the length limit.
98 static constexpr size_t kMaxExtraDescriptorLength = std::numeric_limits<uint16_t>::max();
99 
100 // According to dex file specification, there can be more than 2^16 valid method indexes
101 // but bytecode uses only 16 bits, so higher method indexes are not very useful (though
102 // such methods could be reached through virtual or interface dispatch). Consequently,
103 // dex files with more than 2^16 method indexes are not really used and the profile file
104 // format does not support higher method indexes.
105 static constexpr uint32_t kMaxSupportedMethodIndex = 0xffffu;
106 
107 // Debug flag to ignore checksums when testing if a method or a class is present in the profile.
108 // Used to facilitate testing profile guided compilation across a large number of apps
109 // using the same test profile.
110 static constexpr bool kDebugIgnoreChecksum = false;
111 
112 static constexpr uint8_t kIsMissingTypesEncoding = 6;
113 static constexpr uint8_t kIsMegamorphicEncoding = 7;
114 
115 static_assert(sizeof(ProfileCompilationInfo::kIndividualInlineCacheSize) == sizeof(uint8_t),
116               "InlineCache::kIndividualInlineCacheSize does not have the expect type size");
117 static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMegamorphicEncoding,
118               "InlineCache::kIndividualInlineCacheSize is larger than expected");
119 static_assert(ProfileCompilationInfo::kIndividualInlineCacheSize < kIsMissingTypesEncoding,
120               "InlineCache::kIndividualInlineCacheSize is larger than expected");
121 
122 static constexpr uint32_t kSizeWarningThresholdBytes = 500000U;
123 static constexpr uint32_t kSizeErrorThresholdBytes = 1500000U;
124 
125 static constexpr uint32_t kSizeWarningThresholdBootBytes = 25000000U;
126 static constexpr uint32_t kSizeErrorThresholdBootBytes = 100000000U;
127 
ChecksumMatch(uint32_t dex_file_checksum,uint32_t checksum)128 static bool ChecksumMatch(uint32_t dex_file_checksum, uint32_t checksum) {
129   return kDebugIgnoreChecksum || dex_file_checksum == checksum;
130 }
131 
132 namespace {
133 
134 // Deflate the input buffer `in_buffer`. It returns a buffer of
135 // compressed data for the input buffer of `*compressed_data_size` size.
DeflateBuffer(ArrayRef<const uint8_t> in_buffer,uint32_t * compressed_data_size)136 std::unique_ptr<uint8_t[]> DeflateBuffer(ArrayRef<const uint8_t> in_buffer,
137                                          /*out*/ uint32_t* compressed_data_size) {
138   z_stream strm;
139   strm.zalloc = Z_NULL;
140   strm.zfree = Z_NULL;
141   strm.opaque = Z_NULL;
142   int init_ret = deflateInit(&strm, 1);
143   if (init_ret != Z_OK) {
144     return nullptr;
145   }
146 
147   uint32_t out_size = dchecked_integral_cast<uint32_t>(deflateBound(&strm, in_buffer.size()));
148 
149   std::unique_ptr<uint8_t[]> compressed_buffer(new uint8_t[out_size]);
150   strm.avail_in = in_buffer.size();
151   strm.next_in = const_cast<uint8_t*>(in_buffer.data());
152   strm.avail_out = out_size;
153   strm.next_out = &compressed_buffer[0];
154   int ret = deflate(&strm, Z_FINISH);
155   if (ret == Z_STREAM_ERROR) {
156     return nullptr;
157   }
158   *compressed_data_size = out_size - strm.avail_out;
159 
160   int end_ret = deflateEnd(&strm);
161   if (end_ret != Z_OK) {
162     return nullptr;
163   }
164 
165   return compressed_buffer;
166 }
167 
168 // Inflate the data from `in_buffer` into `out_buffer`. The `out_buffer.size()`
169 // is the expected output size of the buffer. It returns Z_STREAM_END on success.
170 // On error, it returns Z_STREAM_ERROR if the compressed data is inconsistent
171 // and Z_DATA_ERROR if the stream ended prematurely or the stream has extra data.
InflateBuffer(ArrayRef<const uint8_t> in_buffer,ArrayRef<uint8_t> out_buffer)172 int InflateBuffer(ArrayRef<const uint8_t> in_buffer, /*out*/ ArrayRef<uint8_t> out_buffer) {
173   /* allocate inflate state */
174   z_stream strm;
175   strm.zalloc = Z_NULL;
176   strm.zfree = Z_NULL;
177   strm.opaque = Z_NULL;
178   strm.avail_in = in_buffer.size();
179   strm.next_in = const_cast<uint8_t*>(in_buffer.data());
180   strm.avail_out = out_buffer.size();
181   strm.next_out = out_buffer.data();
182 
183   int init_ret = inflateInit(&strm);
184   if (init_ret != Z_OK) {
185     return init_ret;
186   }
187 
188   int ret = inflate(&strm, Z_NO_FLUSH);
189   if (strm.avail_in != 0 || strm.avail_out != 0) {
190     return Z_DATA_ERROR;
191   }
192 
193   int end_ret = inflateEnd(&strm);
194   if (end_ret != Z_OK) {
195     return end_ret;
196   }
197 
198   return ret;
199 }
200 
201 }  // anonymous namespace
202 
203 enum class ProfileCompilationInfo::ProfileLoadStatus : uint32_t {
204   kSuccess,
205   kIOError,
206   kBadMagic,
207   kVersionMismatch,
208   kBadData,
209   kMergeError,  // Merging failed. There are too many extra descriptors
210                 // or classes without TypeId referenced by a dex file.
211 };
212 
213 enum class ProfileCompilationInfo::FileSectionType : uint32_t {
214   // The values of section enumerators and data format for individual sections
215   // must not be changed without changing the profile file version. New sections
216   // can be added at the end and they shall be ignored by old versions of ART.
217 
218   // The list of the dex files included in the profile.
219   // There must be exactly one dex file section and it must be first.
220   kDexFiles = 0,
221 
222   // Extra descriptors for referencing classes that do not have a `dex::TypeId`
223   // in the referencing dex file, such as classes from a different dex file
224   // (even outside of the dex files in the profile) or array classes that were
225   // used from other dex files or created through reflection.
226   kExtraDescriptors = 1,
227 
228   // Classes included in the profile.
229   kClasses = 2,
230 
231   // Methods included in the profile, their hotness flags and inline caches.
232   kMethods = 3,
233 
234   // The aggregation counts of the profile, classes and methods. This section is
235   // an optional reserved section not implemented on client yet.
236   kAggregationCounts = 4,
237 
238   // The number of known sections.
239   kNumberOfSections = 5
240 };
241 
242 class ProfileCompilationInfo::FileSectionInfo {
243  public:
244   // Constructor for reading from a `ProfileSource`. Data shall be filled from the source.
FileSectionInfo()245   FileSectionInfo() {}
246 
247   // Constructor for writing to a file.
FileSectionInfo(FileSectionType type,uint32_t file_offset,uint32_t file_size,uint32_t inflated_size)248   FileSectionInfo(FileSectionType type,
249                   uint32_t file_offset,
250                   uint32_t file_size,
251                   uint32_t inflated_size)
252       : type_(type),
253         file_offset_(file_offset),
254         file_size_(file_size),
255         inflated_size_(inflated_size) {}
256 
SetFileOffset(uint32_t file_offset)257   void SetFileOffset(uint32_t file_offset) {
258     DCHECK_EQ(file_offset_, 0u);
259     DCHECK_NE(file_offset, 0u);
260     file_offset_ = file_offset;
261   }
262 
GetType() const263   FileSectionType GetType() const {
264     return type_;
265   }
266 
GetFileOffset() const267   uint32_t GetFileOffset() const {
268     return file_offset_;
269   }
270 
GetFileSize() const271   uint32_t GetFileSize() const {
272     return file_size_;
273   }
274 
GetInflatedSize() const275   uint32_t GetInflatedSize() const {
276     return inflated_size_;
277   }
278 
GetMemSize() const279   uint32_t GetMemSize() const {
280     return inflated_size_ != 0u ? inflated_size_ : file_size_;
281   }
282 
283  private:
284   FileSectionType type_;
285   uint32_t file_offset_;
286   uint32_t file_size_;
287   uint32_t inflated_size_;  // If 0, do not inflate and use data from file directly.
288 };
289 
290 // The file header.
291 class ProfileCompilationInfo::FileHeader {
292  public:
293   // Constructor for reading from a `ProfileSource`. Data shall be filled from the source.
FileHeader()294   FileHeader() {
295     DCHECK(!IsValid());
296   }
297 
298   // Constructor for writing to a file.
FileHeader(const uint8_t * version,uint32_t file_section_count)299   FileHeader(const uint8_t* version, uint32_t file_section_count)
300       : file_section_count_(file_section_count) {
301     static_assert(sizeof(magic_) == sizeof(kProfileMagic));
302     static_assert(sizeof(version_) == sizeof(kProfileVersion));
303     static_assert(sizeof(version_) == sizeof(kProfileVersionForBootImage));
304     memcpy(magic_, kProfileMagic, sizeof(kProfileMagic));
305     memcpy(version_, version, sizeof(version_));
306     DCHECK_LE(file_section_count, kMaxFileSectionCount);
307     DCHECK(IsValid());
308   }
309 
IsValid() const310   bool IsValid() const {
311     return memcmp(magic_, kProfileMagic, sizeof(kProfileMagic)) == 0 &&
312            (memcmp(version_, kProfileVersion, kProfileVersionSize) == 0 ||
313             memcmp(version_, kProfileVersionForBootImage, kProfileVersionSize) == 0) &&
314            file_section_count_ != 0u &&  // The dex files section is mandatory.
315            file_section_count_ <= kMaxFileSectionCount;
316   }
317 
GetVersion() const318   const uint8_t* GetVersion() const {
319     DCHECK(IsValid());
320     return version_;
321   }
322 
323   ProfileLoadStatus InvalidHeaderMessage(/*out*/ std::string* error_msg) const;
324 
GetFileSectionCount() const325   uint32_t GetFileSectionCount() const {
326     DCHECK(IsValid());
327     return file_section_count_;
328   }
329 
330  private:
331   // The upper bound for file section count is used to ensure that there
332   // shall be no arithmetic overflow when calculating size of the header
333   // with section information.
334   static const uint32_t kMaxFileSectionCount;
335 
336   uint8_t magic_[4] = {0, 0, 0, 0};
337   uint8_t version_[4] = {0, 0, 0, 0};
338   uint32_t file_section_count_ = 0u;
339 };
340 
341 const uint32_t ProfileCompilationInfo::FileHeader::kMaxFileSectionCount =
342     (std::numeric_limits<uint32_t>::max() - sizeof(FileHeader)) / sizeof(FileSectionInfo);
343 
344 ProfileCompilationInfo::ProfileLoadStatus
InvalidHeaderMessage(std::string * error_msg) const345 ProfileCompilationInfo::FileHeader::InvalidHeaderMessage(/*out*/ std::string* error_msg) const {
346   if (memcmp(magic_, kProfileMagic, sizeof(kProfileMagic)) != 0) {
347     *error_msg = "Profile missing magic.";
348     return ProfileLoadStatus::kBadMagic;
349   }
350   if (memcmp(version_, kProfileVersion, sizeof(kProfileVersion)) != 0 &&
351       memcmp(version_, kProfileVersion, sizeof(kProfileVersionForBootImage)) != 0) {
352     *error_msg = "Profile version mismatch.";
353     return ProfileLoadStatus::kVersionMismatch;
354   }
355   if (file_section_count_ == 0u) {
356     *error_msg = "Missing mandatory dex files section.";
357     return ProfileLoadStatus::kBadData;
358   }
359   DCHECK_GT(file_section_count_, kMaxFileSectionCount);
360   *error_msg ="Too many sections.";
361   return ProfileLoadStatus::kBadData;
362 }
363 
364 /**
365  * Encapsulate the source of profile data for loading.
366  * The source can be either a plain file or a zip file.
367  * For zip files, the profile entry will be extracted to
368  * the memory map.
369  */
370 class ProfileCompilationInfo::ProfileSource {
371  public:
372   /**
373    * Create a profile source for the given fd. The ownership of the fd
374    * remains to the caller; as this class will not attempt to close it at any
375    * point.
376    */
Create(int32_t fd)377   static ProfileSource* Create(int32_t fd) {
378     DCHECK_GT(fd, -1);
379     return new ProfileSource(fd, MemMap::Invalid());
380   }
381 
382   /**
383    * Create a profile source backed by a memory map. The map can be null in
384    * which case it will the treated as an empty source.
385    */
Create(MemMap && mem_map)386   static ProfileSource* Create(MemMap&& mem_map) {
387     return new ProfileSource(/*fd*/ -1, std::move(mem_map));
388   }
389 
390   // Seek to the given offset in the source.
391   bool Seek(off_t offset);
392 
393   /**
394    * Read bytes from this source.
395    * Reading will advance the current source position so subsequent
396    * invocations will read from the las position.
397    */
398   ProfileLoadStatus Read(void* buffer,
399                          size_t byte_count,
400                          const std::string& debug_stage,
401                          std::string* error);
402 
403   /** Return true if the source has 0 data. */
404   bool HasEmptyContent() const;
405 
406  private:
ProfileSource(int32_t fd,MemMap && mem_map)407   ProfileSource(int32_t fd, MemMap&& mem_map)
408       : fd_(fd), mem_map_(std::move(mem_map)), mem_map_cur_(0) {}
409 
IsMemMap() const410   bool IsMemMap() const {
411     return fd_ == -1;
412   }
413 
414   int32_t fd_;  // The fd is not owned by this class.
415   MemMap mem_map_;
416   size_t mem_map_cur_;  // Current position in the map to read from.
417 };
418 
419 // A helper structure to make sure we don't read past our buffers in the loops.
420 // Also used for writing but the buffer should be pre-sized correctly for that, so we
421 // DCHECK() we do not write beyond the end, rather than returning `false` on failure.
422 class ProfileCompilationInfo::SafeBuffer {
423  public:
SafeBuffer()424   SafeBuffer()
425       : storage_(nullptr),
426         ptr_current_(nullptr),
427         ptr_end_(nullptr) {}
428 
SafeBuffer(size_t size)429   explicit SafeBuffer(size_t size)
430       : storage_(new uint8_t[size]),
431         ptr_current_(storage_.get()),
432         ptr_end_(ptr_current_ + size) {}
433 
434   // Reads an uint value and advances the current pointer.
435   template <typename T>
ReadUintAndAdvance(T * value)436   bool ReadUintAndAdvance(/*out*/ T* value) {
437     static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
438     if (sizeof(T) > GetAvailableBytes()) {
439       return false;
440     }
441     *value = 0;
442     for (size_t i = 0; i < sizeof(T); i++) {
443       *value += ptr_current_[i] << (i * kBitsPerByte);
444     }
445     ptr_current_ += sizeof(T);
446     return true;
447   }
448 
449   // Reads a length-prefixed string as `std::string_view` and advances the current pointer.
450   // The length is `uint16_t`.
ReadStringAndAdvance(std::string_view * value)451   bool ReadStringAndAdvance(/*out*/ std::string_view* value) {
452     uint16_t length;
453     if (!ReadUintAndAdvance(&length)) {
454       return false;
455     }
456     if (length > GetAvailableBytes()) {
457       return false;
458     }
459     const void* null_char = memchr(GetCurrentPtr(), 0, length);
460     if (null_char != nullptr) {
461       // Embedded nulls are invalid.
462       return false;
463     }
464     *value = std::string_view(reinterpret_cast<const char*>(GetCurrentPtr()), length);
465     Advance(length);
466     return true;
467   }
468 
469   // Compares the given data with the content at the current pointer.
470   // If the contents are equal it advances the current pointer by data_size.
CompareAndAdvance(const uint8_t * data,size_t data_size)471   bool CompareAndAdvance(const uint8_t* data, size_t data_size) {
472     if (data_size > GetAvailableBytes()) {
473       return false;
474     }
475     if (memcmp(ptr_current_, data, data_size) == 0) {
476       ptr_current_ += data_size;
477       return true;
478     }
479     return false;
480   }
481 
WriteAndAdvance(const void * data,size_t data_size)482   void WriteAndAdvance(const void* data, size_t data_size) {
483     DCHECK_LE(data_size, GetAvailableBytes());
484     memcpy(ptr_current_, data, data_size);
485     ptr_current_ += data_size;
486   }
487 
488   template <typename T>
WriteUintAndAdvance(T value)489   void WriteUintAndAdvance(T value) {
490     static_assert(std::is_integral_v<T>);
491     WriteAndAdvance(&value, sizeof(value));
492   }
493 
494   // Deflate a filled buffer. Replaces the internal buffer with a new one, also filled.
Deflate()495   bool Deflate() {
496     DCHECK_EQ(GetAvailableBytes(), 0u);
497     DCHECK_NE(Size(), 0u);
498     ArrayRef<const uint8_t> in_buffer(Get(), Size());
499     uint32_t output_size = 0;
500     std::unique_ptr<uint8_t[]> compressed_buffer = DeflateBuffer(in_buffer, &output_size);
501     if (compressed_buffer == nullptr) {
502       return false;
503     }
504     storage_ = std::move(compressed_buffer);
505     ptr_current_ = storage_.get() + output_size;
506     ptr_end_ = ptr_current_;
507     return true;
508   }
509 
510   // Inflate an unread buffer. Replaces the internal buffer with a new one, also unread.
Inflate(size_t uncompressed_data_size)511   bool Inflate(size_t uncompressed_data_size) {
512     DCHECK(ptr_current_ == storage_.get());
513     DCHECK_NE(Size(), 0u);
514     ArrayRef<const uint8_t> in_buffer(Get(), Size());
515     SafeBuffer uncompressed_buffer(uncompressed_data_size);
516     ArrayRef<uint8_t> out_buffer(uncompressed_buffer.Get(), uncompressed_data_size);
517     int ret = InflateBuffer(in_buffer, out_buffer);
518     if (ret != Z_STREAM_END) {
519       return false;
520     }
521     Swap(uncompressed_buffer);
522     DCHECK(ptr_current_ == storage_.get());
523     return true;
524   }
525 
526   // Advances current pointer by data_size.
Advance(size_t data_size)527   void Advance(size_t data_size) {
528     DCHECK_LE(data_size, GetAvailableBytes());
529     ptr_current_ += data_size;
530   }
531 
532   // Returns the count of unread bytes.
GetAvailableBytes() const533   size_t GetAvailableBytes() const {
534     DCHECK_LE(static_cast<void*>(ptr_current_), static_cast<void*>(ptr_end_));
535     return (ptr_end_ - ptr_current_) * sizeof(*ptr_current_);
536   }
537 
538   // Returns the current pointer.
GetCurrentPtr()539   uint8_t* GetCurrentPtr() {
540     return ptr_current_;
541   }
542 
543   // Get the underlying raw buffer.
Get()544   uint8_t* Get() {
545     return storage_.get();
546   }
547 
548   // Get the size of the raw buffer.
Size() const549   size_t Size() const {
550     return ptr_end_ - storage_.get();
551   }
552 
Swap(SafeBuffer & other)553   void Swap(SafeBuffer& other) {
554     std::swap(storage_, other.storage_);
555     std::swap(ptr_current_, other.ptr_current_);
556     std::swap(ptr_end_, other.ptr_end_);
557   }
558 
559  private:
560   std::unique_ptr<uint8_t[]> storage_;
561   uint8_t* ptr_current_;
562   uint8_t* ptr_end_;
563 };
564 
ProfileCompilationInfo(ArenaPool * custom_arena_pool,bool for_boot_image)565 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool, bool for_boot_image)
566     : default_arena_pool_(),
567       allocator_(custom_arena_pool),
568       info_(allocator_.Adapter(kArenaAllocProfile)),
569       profile_key_map_(std::less<const std::string_view>(), allocator_.Adapter(kArenaAllocProfile)),
570       extra_descriptors_(),
571       extra_descriptors_indexes_(ExtraDescriptorHash(&extra_descriptors_),
572                                  ExtraDescriptorEquals(&extra_descriptors_)) {
573   memcpy(version_,
574          for_boot_image ? kProfileVersionForBootImage : kProfileVersion,
575          kProfileVersionSize);
576 }
577 
ProfileCompilationInfo(ArenaPool * custom_arena_pool)578 ProfileCompilationInfo::ProfileCompilationInfo(ArenaPool* custom_arena_pool)
579     : ProfileCompilationInfo(custom_arena_pool, /*for_boot_image=*/ false) { }
580 
ProfileCompilationInfo()581 ProfileCompilationInfo::ProfileCompilationInfo()
582     : ProfileCompilationInfo(/*for_boot_image=*/ false) { }
583 
ProfileCompilationInfo(bool for_boot_image)584 ProfileCompilationInfo::ProfileCompilationInfo(bool for_boot_image)
585     : ProfileCompilationInfo(&default_arena_pool_, for_boot_image) { }
586 
~ProfileCompilationInfo()587 ProfileCompilationInfo::~ProfileCompilationInfo() {
588   VLOG(profiler) << Dumpable<MemStats>(allocator_.GetMemStats());
589 }
590 
AddClass(const dex::TypeIndex & type_idx)591 void ProfileCompilationInfo::DexPcData::AddClass(const dex::TypeIndex& type_idx) {
592   if (is_megamorphic || is_missing_types) {
593     return;
594   }
595 
596   // Perform an explicit lookup for the type instead of directly emplacing the
597   // element. We do this because emplace() allocates the node before doing the
598   // lookup and if it then finds an identical element, it shall deallocate the
599   // node. For Arena allocations, that's essentially a leak.
600   auto lb = classes.lower_bound(type_idx);
601   if (lb != classes.end() && *lb == type_idx) {
602     // The type index exists.
603     return;
604   }
605 
606   // Check if the adding the type will cause the cache to become megamorphic.
607   if (classes.size() + 1 >= ProfileCompilationInfo::kIndividualInlineCacheSize) {
608     is_megamorphic = true;
609     classes.clear();
610     return;
611   }
612 
613   // The type does not exist and the inline cache will not be megamorphic.
614   classes.emplace_hint(lb, type_idx);
615 }
616 
617 // Transform the actual dex location into a key used to index the dex file in the profile.
618 // See ProfileCompilationInfo#GetProfileDexFileBaseKey as well.
GetProfileDexFileAugmentedKey(const std::string & dex_location,const ProfileSampleAnnotation & annotation)619 std::string ProfileCompilationInfo::GetProfileDexFileAugmentedKey(
620       const std::string& dex_location,
621       const ProfileSampleAnnotation& annotation) {
622   std::string base_key = GetProfileDexFileBaseKey(dex_location);
623   return annotation == ProfileSampleAnnotation::kNone
624       ? base_key
625       : base_key + kSampleMetadataSeparator + annotation.GetOriginPackageName();;
626 }
627 
628 // Transform the actual dex location into a base profile key (represented as relative paths).
629 // Note: this is OK because we don't store profiles of different apps into the same file.
630 // Apps with split apks don't cause trouble because each split has a different name and will not
631 // collide with other entries.
GetProfileDexFileBaseKeyView(std::string_view dex_location)632 std::string_view ProfileCompilationInfo::GetProfileDexFileBaseKeyView(
633     std::string_view dex_location) {
634   DCHECK(!dex_location.empty());
635   size_t last_sep_index = dex_location.find_last_of('/');
636   if (last_sep_index == std::string::npos) {
637     return dex_location;
638   } else {
639     DCHECK(last_sep_index < dex_location.size());
640     return dex_location.substr(last_sep_index + 1);
641   }
642 }
643 
GetProfileDexFileBaseKey(const std::string & dex_location)644 std::string ProfileCompilationInfo::GetProfileDexFileBaseKey(const std::string& dex_location) {
645   // Note: Conversions between std::string and std::string_view.
646   return std::string(GetProfileDexFileBaseKeyView(dex_location));
647 }
648 
GetBaseKeyViewFromAugmentedKey(std::string_view profile_key)649 std::string_view ProfileCompilationInfo::GetBaseKeyViewFromAugmentedKey(
650     std::string_view profile_key) {
651   size_t pos = profile_key.rfind(kSampleMetadataSeparator);
652   return (pos == std::string::npos) ? profile_key : profile_key.substr(0, pos);
653 }
654 
GetBaseKeyFromAugmentedKey(const std::string & profile_key)655 std::string ProfileCompilationInfo::GetBaseKeyFromAugmentedKey(
656     const std::string& profile_key) {
657   // Note: Conversions between std::string and std::string_view.
658   return std::string(GetBaseKeyViewFromAugmentedKey(profile_key));
659 }
660 
MigrateAnnotationInfo(const std::string & base_key,const std::string & augmented_key)661 std::string ProfileCompilationInfo::MigrateAnnotationInfo(
662     const std::string& base_key,
663     const std::string& augmented_key) {
664   size_t pos = augmented_key.rfind(kSampleMetadataSeparator);
665   return (pos == std::string::npos)
666       ? base_key
667       : base_key + augmented_key.substr(pos);
668 }
669 
GetAnnotationFromKey(const std::string & augmented_key)670 ProfileCompilationInfo::ProfileSampleAnnotation ProfileCompilationInfo::GetAnnotationFromKey(
671      const std::string& augmented_key) {
672   size_t pos = augmented_key.rfind(kSampleMetadataSeparator);
673   return (pos == std::string::npos)
674       ? ProfileSampleAnnotation::kNone
675       : ProfileSampleAnnotation(augmented_key.substr(pos + 1));
676 }
677 
AddMethods(const std::vector<ProfileMethodInfo> & methods,MethodHotness::Flag flags,const ProfileSampleAnnotation & annotation,bool is_test)678 bool ProfileCompilationInfo::AddMethods(const std::vector<ProfileMethodInfo>& methods,
679                                         MethodHotness::Flag flags,
680                                         const ProfileSampleAnnotation& annotation,
681                                         bool is_test) {
682   for (const ProfileMethodInfo& method : methods) {
683     if (!AddMethod(method, flags, annotation, is_test)) {
684       return false;
685     }
686   }
687   return true;
688 }
689 
FindOrCreateTypeIndex(const DexFile & dex_file,TypeReference class_ref)690 dex::TypeIndex ProfileCompilationInfo::FindOrCreateTypeIndex(const DexFile& dex_file,
691                                                              TypeReference class_ref) {
692   DCHECK(class_ref.dex_file != nullptr);
693   DCHECK_LT(class_ref.TypeIndex().index_, class_ref.dex_file->NumTypeIds());
694   if (class_ref.dex_file == &dex_file) {
695     // We can use the type index from the `class_ref` as it's a valid index in the `dex_file`.
696     return class_ref.TypeIndex();
697   }
698   // Try to find a `TypeId` in the method's dex file.
699   std::string_view descriptor = class_ref.dex_file->GetTypeDescriptorView(class_ref.TypeIndex());
700   return FindOrCreateTypeIndex(dex_file, descriptor);
701 }
702 
FindOrCreateTypeIndex(const DexFile & dex_file,std::string_view descriptor)703 dex::TypeIndex ProfileCompilationInfo::FindOrCreateTypeIndex(const DexFile& dex_file,
704                                                              std::string_view descriptor) {
705   const dex::TypeId* type_id = dex_file.FindTypeId(descriptor);
706   if (type_id != nullptr) {
707     return dex_file.GetIndexForTypeId(*type_id);
708   }
709   // Try to find an existing extra descriptor.
710   uint32_t num_type_ids = dex_file.NumTypeIds();
711   uint32_t max_artificial_ids = DexFile::kDexNoIndex16 - num_type_ids;
712   // Check descriptor length for "extra descriptor". We are using `uint16_t` as prefix.
713   if (UNLIKELY(descriptor.size() > kMaxExtraDescriptorLength)) {
714     return dex::TypeIndex();  // Invalid.
715   }
716   auto it = extra_descriptors_indexes_.find(descriptor);
717   if (it != extra_descriptors_indexes_.end()) {
718     return (*it < max_artificial_ids) ? dex::TypeIndex(num_type_ids + *it) : dex::TypeIndex();
719   }
720   // Check if inserting the extra descriptor yields a valid artificial type index.
721   if (UNLIKELY(extra_descriptors_.size() >= max_artificial_ids)) {
722     return dex::TypeIndex();  // Invalid.
723   }
724   // Add the descriptor to extra descriptors and return the artificial type index.
725   ExtraDescriptorIndex new_extra_descriptor_index = AddExtraDescriptor(descriptor);
726   DCHECK_LT(new_extra_descriptor_index, max_artificial_ids);
727   return dex::TypeIndex(num_type_ids + new_extra_descriptor_index);
728 }
729 
AddClass(const DexFile & dex_file,std::string_view descriptor,const ProfileSampleAnnotation & annotation)730 bool ProfileCompilationInfo::AddClass(const DexFile& dex_file,
731                                       std::string_view descriptor,
732                                       const ProfileSampleAnnotation& annotation) {
733   DexFileData* const data = GetOrAddDexFileData(&dex_file, annotation);
734   if (data == nullptr) {  // checksum mismatch
735     return false;
736   }
737   dex::TypeIndex type_index = FindOrCreateTypeIndex(dex_file, descriptor);
738   if (!type_index.IsValid()) {
739     return false;
740   }
741   data->class_set.insert(type_index);
742   return true;
743 }
744 
MergeWith(const std::string & filename)745 bool ProfileCompilationInfo::MergeWith(const std::string& filename) {
746   std::string error;
747 #ifdef _WIN32
748   int flags = O_RDONLY;
749 #else
750   int flags = O_RDONLY | O_NOFOLLOW | O_CLOEXEC;
751 #endif
752   ScopedFlock profile_file =
753       LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
754 
755   if (profile_file.get() == nullptr) {
756     LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
757     return false;
758   }
759 
760   int fd = profile_file->Fd();
761 
762   ProfileLoadStatus status = LoadInternal(fd, &error);
763   if (status == ProfileLoadStatus::kSuccess) {
764     return true;
765   }
766 
767   LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
768   return false;
769 }
770 
Load(const std::string & filename,bool clear_if_invalid)771 bool ProfileCompilationInfo::Load(const std::string& filename, bool clear_if_invalid) {
772   ScopedTrace trace(__PRETTY_FUNCTION__);
773   std::string error;
774 
775   if (!IsEmpty()) {
776     return false;
777   }
778 
779 #ifdef _WIN32
780   int flags = O_RDWR;
781 #else
782   int flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
783 #endif
784   // There's no need to fsync profile data right away. We get many chances
785   // to write it again in case something goes wrong. We can rely on a simple
786   // close(), no sync, and let to the kernel decide when to write to disk.
787   ScopedFlock profile_file =
788       LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
789 
790   if (profile_file.get() == nullptr) {
791     if (clear_if_invalid && errno == ENOENT) {
792       return true;
793     }
794     LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
795     return false;
796   }
797 
798   int fd = profile_file->Fd();
799 
800   ProfileLoadStatus status = LoadInternal(fd, &error);
801   if (status == ProfileLoadStatus::kSuccess) {
802     return true;
803   }
804 
805   if (clear_if_invalid &&
806       ((status == ProfileLoadStatus::kBadMagic) ||
807        (status == ProfileLoadStatus::kVersionMismatch) ||
808        (status == ProfileLoadStatus::kBadData))) {
809     LOG(WARNING) << "Clearing bad or obsolete profile data from file "
810                  << filename << ": " << error;
811     // When ART Service is enabled, this is the only place where we mutate a profile in place.
812     // TODO(jiakaiz): Get rid of this.
813     if (profile_file->ClearContent()) {
814       return true;
815     } else {
816       PLOG(WARNING) << "Could not clear profile file: " << filename;
817       return false;
818     }
819   }
820 
821   LOG(WARNING) << "Could not load profile data from file " << filename << ": " << error;
822   return false;
823 }
824 
Save(const std::string & filename,uint64_t * bytes_written)825 bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_written) {
826   ScopedTrace trace(__PRETTY_FUNCTION__);
827 
828 #ifndef ART_TARGET_ANDROID
829   return SaveFallback(filename, bytes_written);
830 #else
831   // Prior to U, SELinux policy doesn't allow apps to create profile files.
832   // Additionally, when installd is being used for dexopt, it acquires a flock when working on a
833   // profile. It's unclear to us whether the flock means that the file at the fd shouldn't change or
834   // that the file at the path shouldn't change, especially when the installd code is modified by
835   // partners. Therefore, we fall back to using a flock as well just to be safe.
836   if (!android::modules::sdklevel::IsAtLeastU() ||
837       !android::base::GetBoolProperty("dalvik.vm.useartservice", /*default_value=*/false)) {
838     return SaveFallback(filename, bytes_written);
839   }
840 
841   std::string tmp_filename = filename + ".XXXXXX.tmp";
842   // mkstemps creates the file with permissions 0600, which is the desired permissions, so there's
843   // no need to chmod.
844   android::base::unique_fd fd(mkostemps(tmp_filename.data(), /*suffixlen=*/4, O_CLOEXEC));
845   if (fd.get() < 0) {
846     PLOG(WARNING) << "Failed to create temp profile file for " << filename;
847     return false;
848   }
849 
850   // In case anything goes wrong.
851   auto remove_tmp_file = android::base::make_scope_guard([&]() {
852     if (unlink(tmp_filename.c_str()) != 0) {
853       PLOG(WARNING) << "Failed to remove temp profile file " << tmp_filename;
854     }
855   });
856 
857   bool result = Save(fd.get());
858   if (!result) {
859     VLOG(profiler) << "Failed to save profile info to temp profile file " << tmp_filename;
860     return false;
861   }
862 
863   fd.reset();
864 
865   // Move the temp profile file to the final location.
866   if (rename(tmp_filename.c_str(), filename.c_str()) != 0) {
867     PLOG(WARNING) << "Failed to commit profile file " << filename;
868     return false;
869   }
870 
871   remove_tmp_file.Disable();
872 
873   int64_t size = OS::GetFileSizeBytes(filename.c_str());
874   if (size != -1) {
875     VLOG(profiler) << "Successfully saved profile info to " << filename << " Size: " << size;
876     if (bytes_written != nullptr) {
877       *bytes_written = static_cast<uint64_t>(size);
878     }
879   } else {
880     VLOG(profiler) << "Saved profile info to " << filename
881                    << " but failed to get size: " << strerror(errno);
882   }
883 
884   return true;
885 #endif
886 }
887 
SaveFallback(const std::string & filename,uint64_t * bytes_written)888 bool ProfileCompilationInfo::SaveFallback(const std::string& filename, uint64_t* bytes_written) {
889   std::string error;
890 #ifdef _WIN32
891   int flags = O_WRONLY | O_CREAT;
892 #else
893   int flags = O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_CREAT;
894 #endif
895   // There's no need to fsync profile data right away. We get many chances
896   // to write it again in case something goes wrong. We can rely on a simple
897   // close(), no sync, and let to the kernel decide when to write to disk.
898   ScopedFlock profile_file =
899       LockedFile::Open(filename.c_str(), flags, /*block=*/false, &error);
900   if (profile_file.get() == nullptr) {
901     LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
902     return false;
903   }
904 
905   int fd = profile_file->Fd();
906 
907   // We need to clear the data because we don't support appending to the profiles yet.
908   if (!profile_file->ClearContent()) {
909     PLOG(WARNING) << "Could not clear profile file: " << filename;
910     return false;
911   }
912 
913   // This doesn't need locking because we are trying to lock the file for exclusive
914   // access and fail immediately if we can't.
915   bool result = Save(fd);
916   if (result) {
917     int64_t size = OS::GetFileSizeBytes(filename.c_str());
918     if (size != -1) {
919       VLOG(profiler)
920         << "Successfully saved profile info to " << filename << " Size: "
921         << size;
922       if (bytes_written != nullptr) {
923         *bytes_written = static_cast<uint64_t>(size);
924       }
925     } else {
926       VLOG(profiler) << "Saved profile info to " << filename
927                      << " but failed to get size: " << strerror(errno);
928     }
929   } else {
930     VLOG(profiler) << "Failed to save profile info to " << filename;
931   }
932   return result;
933 }
934 
935 // Returns true if all the bytes were successfully written to the file descriptor.
WriteBuffer(int fd,const void * buffer,size_t byte_count)936 static bool WriteBuffer(int fd, const void* buffer, size_t byte_count) {
937   while (byte_count > 0) {
938     int bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer, byte_count));
939     if (bytes_written == -1) {
940       return false;
941     }
942     byte_count -= bytes_written;  // Reduce the number of remaining bytes.
943     reinterpret_cast<const uint8_t*&>(buffer) += bytes_written;  // Move the buffer forward.
944   }
945   return true;
946 }
947 
948 /**
949  * Serialization format:
950  *
951  * The file starts with a header and section information:
952  *   FileHeader
953  *   FileSectionInfo[]
954  * The first FileSectionInfo must be for the DexFiles section.
955  *
956  * The rest of the file is allowed to contain different sections in any order,
957  * at arbitrary offsets, with any gaps betweeen them and each section can be
958  * either plaintext or separately zipped. However, we're writing sections
959  * without any gaps with the following order and compression:
960  *   DexFiles - mandatory, plaintext
961  *   ExtraDescriptors - optional, zipped
962  *   Classes - optional, zipped
963  *   Methods - optional, zipped
964  *   AggregationCounts - optional, zipped, server-side
965  *
966  * DexFiles:
967  *    number_of_dex_files
968  *    (checksum,num_type_ids,num_method_ids,profile_key)[number_of_dex_files]
969  * where `profile_key` is a length-prefixed string, the length is `uint16_t`.
970  *
971  * ExtraDescriptors:
972  *    number_of_extra_descriptors
973  *    (extra_descriptor)[number_of_extra_descriptors]
974  * where `extra_descriptor` is a length-prefixed string, the length is `uint16_t`.
975  *
976  * Classes contains records for any number of dex files, each consisting of:
977  *    profile_index  // Index of the dex file in DexFiles section.
978  *    number_of_classes
979  *    type_index_diff[number_of_classes]
980  * where instead of storing plain sorted type indexes, we store their differences
981  * as smaller numbers are likely to compress better.
982  *
983  * Methods contains records for any number of dex files, each consisting of:
984  *    profile_index  // Index of the dex file in DexFiles section.
985  *    following_data_size  // For easy skipping of remaining data when dex file is filtered out.
986  *    method_flags
987  *    bitmap_data
988  *    method_encoding[]  // Until the size indicated by `following_data_size`.
989  * where `method_flags` is a union of flags recorded for methods in the referenced dex file,
990  * `bitmap_data` contains `num_method_ids` bits for each bit set in `method_flags` other
991  * than "hot" (the size of `bitmap_data` is rounded up to whole bytes) and `method_encoding[]`
992  * contains data for hot methods. The `method_encoding` is:
993  *    method_index_diff
994  *    number_of_inline_caches
995  *    inline_cache_encoding[number_of_inline_caches]
996  * where differences in method indexes are used for better compression,
997  * and the `inline_cache_encoding` is
998  *    dex_pc
999  *    (M|dex_map_size)
1000  *    type_index_diff[dex_map_size]
1001  * where `M` stands for special encodings indicating missing types (kIsMissingTypesEncoding)
1002  * or memamorphic call (kIsMegamorphicEncoding) which both imply `dex_map_size == 0`.
1003  **/
Save(int fd)1004 bool ProfileCompilationInfo::Save(int fd) {
1005   uint64_t start = NanoTime();
1006   ScopedTrace trace(__PRETTY_FUNCTION__);
1007   DCHECK_GE(fd, 0);
1008 
1009   // Collect uncompressed section sizes.
1010   // Use `uint64_t` and assume this cannot overflow as we would have run out of memory.
1011   uint64_t extra_descriptors_section_size = 0u;
1012   if (!extra_descriptors_.empty()) {
1013     extra_descriptors_section_size += sizeof(uint16_t);  // Number of descriptors.
1014     for (const std::string& descriptor : extra_descriptors_) {
1015       // Length-prefixed string, the length is `uint16_t`.
1016       extra_descriptors_section_size += sizeof(uint16_t) + descriptor.size();
1017     }
1018   }
1019   uint64_t dex_files_section_size = sizeof(ProfileIndexType);  // Number of dex files.
1020   uint64_t classes_section_size = 0u;
1021   uint64_t methods_section_size = 0u;
1022   DCHECK_LE(info_.size(), MaxProfileIndex());
1023   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1024     if (dex_data->profile_key.size() > kMaxDexFileKeyLength) {
1025       LOG(WARNING) << "DexFileKey exceeds allocated limit";
1026       return false;
1027     }
1028     dex_files_section_size +=
1029         3 * sizeof(uint32_t) +  // Checksum, num_type_ids, num_method_ids.
1030         // Length-prefixed string, the length is `uint16_t`.
1031         sizeof(uint16_t) + dex_data->profile_key.size();
1032     classes_section_size += dex_data->ClassesDataSize();
1033     methods_section_size += dex_data->MethodsDataSize();
1034   }
1035 
1036   const uint32_t file_section_count =
1037       /* dex files */ 1u +
1038       /* extra descriptors */ (extra_descriptors_section_size != 0u ? 1u : 0u) +
1039       /* classes */ (classes_section_size != 0u ? 1u : 0u) +
1040       /* methods */ (methods_section_size != 0u ? 1u : 0u);
1041   uint64_t header_and_infos_size =
1042       sizeof(FileHeader) + file_section_count * sizeof(FileSectionInfo);
1043 
1044   // Check size limit. Allow large profiles for non target builds for the case
1045   // where we are merging many profiles to generate a boot image profile.
1046   uint64_t total_uncompressed_size =
1047       header_and_infos_size +
1048       dex_files_section_size +
1049       extra_descriptors_section_size +
1050       classes_section_size +
1051       methods_section_size;
1052   VLOG(profiler) << "Required capacity: " << total_uncompressed_size << " bytes.";
1053   if (total_uncompressed_size > GetSizeErrorThresholdBytes()) {
1054     LOG(WARNING) << "Profile data size exceeds "
1055                  << GetSizeErrorThresholdBytes()
1056                  << " bytes. Profile will not be written to disk."
1057                  << " It requires " << total_uncompressed_size << " bytes.";
1058     return false;
1059   }
1060 
1061   // Start with an invalid file header and section infos.
1062   DCHECK_EQ(lseek(fd, 0, SEEK_CUR), 0);
1063   constexpr uint32_t kMaxNumberOfSections = enum_cast<uint32_t>(FileSectionType::kNumberOfSections);
1064   constexpr uint64_t kMaxHeaderAndInfosSize =
1065       sizeof(FileHeader) + kMaxNumberOfSections * sizeof(FileSectionInfo);
1066   DCHECK_LE(header_and_infos_size, kMaxHeaderAndInfosSize);
1067   std::array<uint8_t, kMaxHeaderAndInfosSize> placeholder;
1068   memset(placeholder.data(), 0, header_and_infos_size);
1069   if (!WriteBuffer(fd, placeholder.data(), header_and_infos_size)) {
1070     return false;
1071   }
1072 
1073   std::array<FileSectionInfo, kMaxNumberOfSections> section_infos;
1074   size_t section_index = 0u;
1075   uint32_t file_offset = header_and_infos_size;
1076   auto add_section_info = [&](FileSectionType type, uint32_t file_size, uint32_t inflated_size) {
1077     DCHECK_LT(section_index, section_infos.size());
1078     section_infos[section_index] = FileSectionInfo(type, file_offset, file_size, inflated_size);
1079     file_offset += file_size;
1080     section_index += 1u;
1081   };
1082 
1083   // Write the dex files section.
1084   {
1085     SafeBuffer buffer(dex_files_section_size);
1086     buffer.WriteUintAndAdvance(dchecked_integral_cast<ProfileIndexType>(info_.size()));
1087     for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1088       buffer.WriteUintAndAdvance(dex_data->checksum);
1089       buffer.WriteUintAndAdvance(dex_data->num_type_ids);
1090       buffer.WriteUintAndAdvance(dex_data->num_method_ids);
1091       buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(dex_data->profile_key.size()));
1092       buffer.WriteAndAdvance(dex_data->profile_key.c_str(), dex_data->profile_key.size());
1093     }
1094     DCHECK_EQ(buffer.GetAvailableBytes(), 0u);
1095     // Write the dex files section uncompressed.
1096     if (!WriteBuffer(fd, buffer.Get(), dex_files_section_size)) {
1097       return false;
1098     }
1099     add_section_info(FileSectionType::kDexFiles, dex_files_section_size, /*inflated_size=*/ 0u);
1100   }
1101 
1102   // Write the extra descriptors section.
1103   if (extra_descriptors_section_size != 0u) {
1104     SafeBuffer buffer(extra_descriptors_section_size);
1105     buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(extra_descriptors_.size()));
1106     for (const std::string& descriptor : extra_descriptors_) {
1107       buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(descriptor.size()));
1108       buffer.WriteAndAdvance(descriptor.c_str(), descriptor.size());
1109     }
1110     if (!buffer.Deflate()) {
1111       return false;
1112     }
1113     if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1114       return false;
1115     }
1116     add_section_info(
1117         FileSectionType::kExtraDescriptors, buffer.Size(), extra_descriptors_section_size);
1118   }
1119 
1120   // Write the classes section.
1121   if (classes_section_size != 0u) {
1122     SafeBuffer buffer(classes_section_size);
1123     for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1124       dex_data->WriteClasses(buffer);
1125     }
1126     if (!buffer.Deflate()) {
1127       return false;
1128     }
1129     if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1130       return false;
1131     }
1132     add_section_info(FileSectionType::kClasses, buffer.Size(), classes_section_size);
1133   }
1134 
1135   // Write the methods section.
1136   if (methods_section_size != 0u) {
1137     SafeBuffer buffer(methods_section_size);
1138     for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1139       dex_data->WriteMethods(buffer);
1140     }
1141     if (!buffer.Deflate()) {
1142       return false;
1143     }
1144     if (!WriteBuffer(fd, buffer.Get(), buffer.Size())) {
1145       return false;
1146     }
1147     add_section_info(FileSectionType::kMethods, buffer.Size(), methods_section_size);
1148   }
1149 
1150   if (file_offset > GetSizeWarningThresholdBytes()) {
1151     LOG(WARNING) << "Profile data size exceeds "
1152         << GetSizeWarningThresholdBytes()
1153         << " It has " << file_offset << " bytes";
1154   }
1155 
1156   // Write section infos.
1157   if (lseek64(fd, sizeof(FileHeader), SEEK_SET) != sizeof(FileHeader)) {
1158     return false;
1159   }
1160   SafeBuffer section_infos_buffer(section_index * 4u * sizeof(uint32_t));
1161   for (size_t i = 0; i != section_index; ++i) {
1162     const FileSectionInfo& info = section_infos[i];
1163     section_infos_buffer.WriteUintAndAdvance(enum_cast<uint32_t>(info.GetType()));
1164     section_infos_buffer.WriteUintAndAdvance(info.GetFileOffset());
1165     section_infos_buffer.WriteUintAndAdvance(info.GetFileSize());
1166     section_infos_buffer.WriteUintAndAdvance(info.GetInflatedSize());
1167   }
1168   DCHECK_EQ(section_infos_buffer.GetAvailableBytes(), 0u);
1169   if (!WriteBuffer(fd, section_infos_buffer.Get(), section_infos_buffer.Size())) {
1170     return false;
1171   }
1172 
1173   // Write header.
1174   FileHeader header(version_, section_index);
1175   if (lseek(fd, 0, SEEK_SET) != 0) {
1176     return false;
1177   }
1178   if (!WriteBuffer(fd, &header, sizeof(FileHeader))) {
1179     return false;
1180   }
1181 
1182   uint64_t total_time = NanoTime() - start;
1183   VLOG(profiler) << "Compressed from "
1184                  << std::to_string(total_uncompressed_size)
1185                  << " to "
1186                  << std::to_string(file_offset);
1187   VLOG(profiler) << "Time to save profile: " << std::to_string(total_time);
1188   return true;
1189 }
1190 
GetOrAddDexFileData(const std::string & profile_key,uint32_t checksum,uint32_t num_type_ids,uint32_t num_method_ids)1191 ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
1192     const std::string& profile_key,
1193     uint32_t checksum,
1194     uint32_t num_type_ids,
1195     uint32_t num_method_ids) {
1196   DCHECK_EQ(profile_key_map_.size(), info_.size());
1197   auto profile_index_it = profile_key_map_.lower_bound(profile_key);
1198   if (profile_index_it == profile_key_map_.end() || profile_index_it->first != profile_key) {
1199     // We did not find the key. Create a new DexFileData if we did not reach the limit.
1200     DCHECK_LE(profile_key_map_.size(), MaxProfileIndex());
1201     if (profile_key_map_.size() == MaxProfileIndex()) {
1202       // Allow only a limited number dex files to be profiled. This allows us to save bytes
1203       // when encoding. For regular profiles this 2^8, and for boot profiles is 2^16
1204       // (well above what we expect for normal applications).
1205       LOG(ERROR) << "Exceeded the maximum number of dex file. Something went wrong";
1206       return nullptr;
1207     }
1208     ProfileIndexType new_profile_index = dchecked_integral_cast<ProfileIndexType>(info_.size());
1209     std::unique_ptr<DexFileData> dex_file_data(new (&allocator_) DexFileData(
1210         &allocator_,
1211         profile_key,
1212         checksum,
1213         new_profile_index,
1214         num_type_ids,
1215         num_method_ids,
1216         IsForBootImage()));
1217     // Record the new data in `profile_key_map_` and `info_`.
1218     std::string_view new_key(dex_file_data->profile_key);
1219     profile_index_it = profile_key_map_.PutBefore(profile_index_it, new_key, new_profile_index);
1220     info_.push_back(std::move(dex_file_data));
1221     DCHECK_EQ(profile_key_map_.size(), info_.size());
1222   }
1223 
1224   ProfileIndexType profile_index = profile_index_it->second;
1225   DexFileData* result = info_[profile_index].get();
1226 
1227   // Check that the checksum matches.
1228   // This may different if for example the dex file was updated and we had a record of the old one.
1229   if (result->checksum != checksum) {
1230     LOG(WARNING) << "Checksum mismatch for dex " << profile_key;
1231     return nullptr;
1232   }
1233 
1234   // DCHECK that profile info map key is consistent with the one stored in the dex file data.
1235   // This should always be the case since since the cache map is managed by ProfileCompilationInfo.
1236   DCHECK_EQ(profile_key, result->profile_key);
1237   DCHECK_EQ(profile_index, result->profile_index);
1238 
1239   if (num_type_ids != result->num_type_ids || num_method_ids != result->num_method_ids) {
1240     // This should not happen... added to help investigating b/65812889.
1241     LOG(ERROR) << "num_type_ids or num_method_ids mismatch for dex " << profile_key
1242         << ", types: expected=" << num_type_ids << " v. actual=" << result->num_type_ids
1243         << ", methods: expected=" << num_method_ids << " actual=" << result->num_method_ids;
1244     return nullptr;
1245   }
1246 
1247   return result;
1248 }
1249 
FindDexData(const std::string & profile_key,uint32_t checksum,bool verify_checksum) const1250 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
1251       const std::string& profile_key,
1252       uint32_t checksum,
1253       bool verify_checksum) const {
1254   const auto profile_index_it = profile_key_map_.find(profile_key);
1255   if (profile_index_it == profile_key_map_.end()) {
1256     return nullptr;
1257   }
1258 
1259   ProfileIndexType profile_index = profile_index_it->second;
1260   const DexFileData* result = info_[profile_index].get();
1261   if (verify_checksum && !ChecksumMatch(result->checksum, checksum)) {
1262     return nullptr;
1263   }
1264   DCHECK_EQ(profile_key, result->profile_key);
1265   DCHECK_EQ(profile_index, result->profile_index);
1266   return result;
1267 }
1268 
FindDexDataUsingAnnotations(const DexFile * dex_file,const ProfileSampleAnnotation & annotation) const1269 const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexDataUsingAnnotations(
1270       const DexFile* dex_file,
1271       const ProfileSampleAnnotation& annotation) const {
1272   if (annotation == ProfileSampleAnnotation::kNone) {
1273     std::string_view profile_key = GetProfileDexFileBaseKeyView(dex_file->GetLocation());
1274     for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1275       if (profile_key == GetBaseKeyViewFromAugmentedKey(dex_data->profile_key)) {
1276         if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1277           return nullptr;
1278         }
1279         return dex_data.get();
1280       }
1281     }
1282   } else {
1283     std::string profile_key = GetProfileDexFileAugmentedKey(dex_file->GetLocation(), annotation);
1284     return FindDexData(profile_key, dex_file->GetLocationChecksum());
1285   }
1286 
1287   return nullptr;
1288 }
1289 
FindAllDexData(const DexFile * dex_file,std::vector<const ProfileCompilationInfo::DexFileData * > * result) const1290 void ProfileCompilationInfo::FindAllDexData(
1291     const DexFile* dex_file,
1292     /*out*/ std::vector<const ProfileCompilationInfo::DexFileData*>* result) const {
1293   std::string_view profile_key = GetProfileDexFileBaseKeyView(dex_file->GetLocation());
1294   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1295     if (profile_key == GetBaseKeyViewFromAugmentedKey(dex_data->profile_key)) {
1296       if (ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1297         result->push_back(dex_data.get());
1298       }
1299     }
1300   }
1301 }
1302 
AddExtraDescriptor(std::string_view extra_descriptor)1303 ProfileCompilationInfo::ExtraDescriptorIndex ProfileCompilationInfo::AddExtraDescriptor(
1304     std::string_view extra_descriptor) {
1305   DCHECK_LE(extra_descriptor.size(), kMaxExtraDescriptorLength);
1306   DCHECK(extra_descriptors_indexes_.find(extra_descriptor) == extra_descriptors_indexes_.end());
1307   ExtraDescriptorIndex new_extra_descriptor_index = extra_descriptors_.size();
1308   DCHECK_LE(new_extra_descriptor_index, kMaxExtraDescriptors);
1309   if (UNLIKELY(new_extra_descriptor_index == kMaxExtraDescriptors)) {
1310     return kMaxExtraDescriptors;  // Cannot add another extra descriptor.
1311   }
1312   // Add the extra descriptor and record the new index.
1313   extra_descriptors_.emplace_back(extra_descriptor);
1314   extra_descriptors_indexes_.insert(new_extra_descriptor_index);
1315   return new_extra_descriptor_index;
1316 }
1317 
AddMethod(const ProfileMethodInfo & pmi,MethodHotness::Flag flags,const ProfileSampleAnnotation & annotation,bool is_test)1318 bool ProfileCompilationInfo::AddMethod(const ProfileMethodInfo& pmi,
1319                                        MethodHotness::Flag flags,
1320                                        const ProfileSampleAnnotation& annotation,
1321                                        bool is_test) {
1322   DexFileData* const data = GetOrAddDexFileData(pmi.ref.dex_file, annotation);
1323   if (data == nullptr) {  // checksum mismatch
1324     return false;
1325   }
1326   if (!data->AddMethod(flags, pmi.ref.index)) {
1327     return false;
1328   }
1329   if ((flags & MethodHotness::kFlagHot) == 0) {
1330     // The method is not hot, do not add inline caches.
1331     return true;
1332   }
1333 
1334   // Add inline caches.
1335   InlineCacheMap* inline_cache = data->FindOrAddHotMethod(pmi.ref.index);
1336   DCHECK(inline_cache != nullptr);
1337 
1338   const dex::MethodId& mid = pmi.ref.GetMethodId();
1339   const DexFile& dex_file = *pmi.ref.dex_file;
1340   const dex::ClassDef* class_def = dex_file.FindClassDef(mid.class_idx_);
1341   // If `is_test` is true, we don't try to look at whether dex_pc fit in the
1342   // code item of that method.
1343   uint32_t dex_pc_max = 0u;
1344   if (is_test) {
1345     dex_pc_max = std::numeric_limits<uint32_t>::max();
1346   } else {
1347     if (class_def == nullptr || dex_file.GetClassData(*class_def) == nullptr) {
1348       return true;
1349     }
1350     std::optional<uint32_t> offset = dex_file.GetCodeItemOffset(*class_def, pmi.ref.index);
1351     if (!offset.has_value()) {
1352       return true;
1353     }
1354     CodeItemInstructionAccessor accessor(dex_file, dex_file.GetCodeItem(offset.value()));
1355     dex_pc_max = accessor.InsnsSizeInCodeUnits();
1356   }
1357 
1358   for (const ProfileMethodInfo::ProfileInlineCache& cache : pmi.inline_caches) {
1359     if (cache.dex_pc >= std::numeric_limits<uint16_t>::max()) {
1360       // Discard entries that don't fit the encoding. This should only apply to
1361       // inlined inline caches. See also `HInliner::GetInlineCacheAOT`.
1362       continue;
1363     }
1364     if (cache.dex_pc >= dex_pc_max) {
1365       // Discard entries for inlined inline caches. We don't support them in
1366       // profiles yet.
1367       continue;
1368     }
1369     if (cache.is_missing_types) {
1370       FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
1371       continue;
1372     }
1373     if  (cache.is_megamorphic) {
1374       FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMegamorphic();
1375       continue;
1376     }
1377     for (const TypeReference& class_ref : cache.classes) {
1378       DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, cache.dex_pc);
1379       if (dex_pc_data->is_missing_types || dex_pc_data->is_megamorphic) {
1380         // Don't bother adding classes if we are missing types or already megamorphic.
1381         break;
1382       }
1383       dex::TypeIndex type_index = FindOrCreateTypeIndex(*pmi.ref.dex_file, class_ref);
1384       if (type_index.IsValid()) {
1385         dex_pc_data->AddClass(type_index);
1386       } else {
1387         // Could not create artificial type index.
1388         dex_pc_data->SetIsMissingTypes();
1389       }
1390     }
1391   }
1392   return true;
1393 }
1394 
1395 // TODO(calin): Fix this API. ProfileCompilationInfo::Load should be static and
1396 // return a unique pointer to a ProfileCompilationInfo upon success.
Load(int fd,bool merge_classes,const ProfileLoadFilterFn & filter_fn)1397 bool ProfileCompilationInfo::Load(
1398     int fd, bool merge_classes, const ProfileLoadFilterFn& filter_fn) {
1399   std::string error;
1400 
1401   ProfileLoadStatus status = LoadInternal(fd, &error, merge_classes, filter_fn);
1402 
1403   if (status == ProfileLoadStatus::kSuccess) {
1404     return true;
1405   } else {
1406     LOG(WARNING) << "Error when reading profile: " << error;
1407     return false;
1408   }
1409 }
1410 
VerifyProfileData(const std::vector<const DexFile * > & dex_files)1411 bool ProfileCompilationInfo::VerifyProfileData(const std::vector<const DexFile*>& dex_files) {
1412   std::unordered_map<std::string_view, const DexFile*> key_to_dex_file;
1413   for (const DexFile* dex_file : dex_files) {
1414     key_to_dex_file.emplace(GetProfileDexFileBaseKeyView(dex_file->GetLocation()), dex_file);
1415   }
1416   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
1417     // We need to remove any annotation from the key during verification.
1418     const auto it = key_to_dex_file.find(GetBaseKeyViewFromAugmentedKey(dex_data->profile_key));
1419     if (it == key_to_dex_file.end()) {
1420       // It is okay if profile contains data for additional dex files.
1421       continue;
1422     }
1423     const DexFile* dex_file = it->second;
1424     const std::string& dex_location = dex_file->GetLocation();
1425     if (!ChecksumMatch(dex_data->checksum, dex_file->GetLocationChecksum())) {
1426       LOG(ERROR) << "Dex checksum mismatch while verifying profile "
1427                  << "dex location " << dex_location << " (checksum="
1428                  << dex_file->GetLocationChecksum() << ", profile checksum="
1429                  << dex_data->checksum;
1430       return false;
1431     }
1432 
1433     if (dex_data->num_method_ids != dex_file->NumMethodIds() ||
1434         dex_data->num_type_ids != dex_file->NumTypeIds()) {
1435       LOG(ERROR) << "Number of type or method ids in dex file and profile don't match."
1436                  << "dex location " << dex_location
1437                  << " dex_file.NumTypeIds=" << dex_file->NumTypeIds()
1438                  << " .v dex_data.num_type_ids=" << dex_data->num_type_ids
1439                  << ", dex_file.NumMethodIds=" << dex_file->NumMethodIds()
1440                  << " v. dex_data.num_method_ids=" << dex_data->num_method_ids;
1441       return false;
1442     }
1443 
1444     // Class and method data should be valid. Verify only in debug builds.
1445     if (kIsDebugBuild) {
1446       // Verify method_encoding.
1447       for (const auto& method_it : dex_data->method_map) {
1448         CHECK_LT(method_it.first, dex_data->num_method_ids);
1449 
1450         // Verify class indices of inline caches.
1451         const InlineCacheMap &inline_cache_map = method_it.second;
1452         for (const auto& inline_cache_it : inline_cache_map) {
1453           const DexPcData& dex_pc_data = inline_cache_it.second;
1454           if (dex_pc_data.is_missing_types || dex_pc_data.is_megamorphic) {
1455             // No class indices to verify.
1456             CHECK(dex_pc_data.classes.empty());
1457             continue;
1458           }
1459 
1460           for (const dex::TypeIndex& type_index : dex_pc_data.classes) {
1461             if (type_index.index_ >= dex_data->num_type_ids) {
1462               CHECK_LT(type_index.index_ - dex_data->num_type_ids, extra_descriptors_.size());
1463             }
1464           }
1465         }
1466       }
1467       // Verify class_ids.
1468       for (const dex::TypeIndex& type_index : dex_data->class_set) {
1469         if (type_index.index_ >= dex_data->num_type_ids) {
1470           CHECK_LT(type_index.index_ - dex_data->num_type_ids, extra_descriptors_.size());
1471         }
1472       }
1473     }
1474   }
1475   return true;
1476 }
1477 
OpenSource(int32_t fd,std::unique_ptr<ProfileSource> * source,std::string * error)1478 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::OpenSource(
1479     int32_t fd,
1480     /*out*/ std::unique_ptr<ProfileSource>* source,
1481     /*out*/ std::string* error) {
1482   if (IsProfileFile(fd)) {
1483     source->reset(ProfileSource::Create(fd));
1484     return ProfileLoadStatus::kSuccess;
1485   } else {
1486     std::unique_ptr<ZipArchive> zip_archive(
1487         ZipArchive::OpenFromFd(DupCloexec(fd), "profile", error));
1488     if (zip_archive.get() == nullptr) {
1489       *error = "Could not open the profile zip archive";
1490       return ProfileLoadStatus::kBadData;
1491     }
1492     std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kDexMetadataProfileEntry, error));
1493     if (zip_entry == nullptr) {
1494       // Allow archives without the profile entry. In this case, create an empty profile.
1495       // This gives more flexible when ure-using archives that may miss the entry.
1496       // (e.g. dex metadata files)
1497       LOG(WARNING) << "Could not find entry " << kDexMetadataProfileEntry
1498           << " in the zip archive. Creating an empty profile.";
1499       source->reset(ProfileSource::Create(MemMap::Invalid()));
1500       return ProfileLoadStatus::kSuccess;
1501     }
1502     if (zip_entry->GetUncompressedLength() == 0) {
1503       *error = "Empty profile entry in the zip archive.";
1504       return ProfileLoadStatus::kBadData;
1505     }
1506 
1507     // TODO(calin) pass along file names to assist with debugging.
1508     MemMap map = zip_entry->MapDirectlyOrExtract(
1509         kDexMetadataProfileEntry, "profile file", error, alignof(ProfileSource));
1510 
1511     if (map.IsValid()) {
1512       source->reset(ProfileSource::Create(std::move(map)));
1513       return ProfileLoadStatus::kSuccess;
1514     } else {
1515       return ProfileLoadStatus::kBadData;
1516     }
1517   }
1518 }
1519 
Seek(off_t offset)1520 bool ProfileCompilationInfo::ProfileSource::Seek(off_t offset) {
1521   DCHECK_GE(offset, 0);
1522   if (IsMemMap()) {
1523     if (offset > static_cast<int64_t>(mem_map_.Size())) {
1524       return false;
1525     }
1526     mem_map_cur_ = offset;
1527     return true;
1528   } else {
1529     if (lseek64(fd_, offset, SEEK_SET) != offset) {
1530       return false;
1531     }
1532     return true;
1533   }
1534 }
1535 
Read(void * buffer,size_t byte_count,const std::string & debug_stage,std::string * error)1536 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ProfileSource::Read(
1537     void* buffer,
1538     size_t byte_count,
1539     const std::string& debug_stage,
1540     std::string* error) {
1541   if (IsMemMap()) {
1542     DCHECK_LE(mem_map_cur_, mem_map_.Size());
1543     if (byte_count > mem_map_.Size() - mem_map_cur_) {
1544       return ProfileLoadStatus::kBadData;
1545     }
1546     memcpy(buffer, mem_map_.Begin() + mem_map_cur_, byte_count);
1547     mem_map_cur_ += byte_count;
1548   } else {
1549     while (byte_count > 0) {
1550       int bytes_read = TEMP_FAILURE_RETRY(read(fd_, buffer, byte_count));;
1551       if (bytes_read == 0) {
1552         *error += "Profile EOF reached prematurely for " + debug_stage;
1553         return ProfileLoadStatus::kBadData;
1554       } else if (bytes_read < 0) {
1555         *error += "Profile IO error for " + debug_stage + strerror(errno);
1556         return ProfileLoadStatus::kIOError;
1557       }
1558       byte_count -= bytes_read;
1559       reinterpret_cast<uint8_t*&>(buffer) += bytes_read;
1560     }
1561   }
1562   return ProfileLoadStatus::kSuccess;
1563 }
1564 
1565 
HasEmptyContent() const1566 bool ProfileCompilationInfo::ProfileSource::HasEmptyContent() const {
1567   if (IsMemMap()) {
1568     return !mem_map_.IsValid() || mem_map_.Size() == 0;
1569   } else {
1570     struct stat stat_buffer;
1571     if (fstat(fd_, &stat_buffer) != 0) {
1572       return false;
1573     }
1574     return stat_buffer.st_size == 0;
1575   }
1576 }
1577 
ReadSectionData(ProfileSource & source,const FileSectionInfo & section_info,SafeBuffer * buffer,std::string * error)1578 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadSectionData(
1579     ProfileSource& source,
1580     const FileSectionInfo& section_info,
1581     /*out*/ SafeBuffer* buffer,
1582     /*out*/ std::string* error) {
1583   DCHECK_EQ(buffer->Size(), 0u);
1584   if (!source.Seek(section_info.GetFileOffset())) {
1585     *error = "Failed to seek to section data.";
1586     return ProfileLoadStatus::kIOError;
1587   }
1588   SafeBuffer temp_buffer(section_info.GetFileSize());
1589   ProfileLoadStatus status = source.Read(
1590       temp_buffer.GetCurrentPtr(), temp_buffer.GetAvailableBytes(), "ReadSectionData", error);
1591   if (status != ProfileLoadStatus::kSuccess) {
1592     return status;
1593   }
1594   if (section_info.GetInflatedSize() != 0u &&
1595       !temp_buffer.Inflate(section_info.GetInflatedSize())) {
1596     *error += "Error uncompressing section data.";
1597     return ProfileLoadStatus::kBadData;
1598   }
1599   buffer->Swap(temp_buffer);
1600   return ProfileLoadStatus::kSuccess;
1601 }
1602 
ReadDexFilesSection(ProfileSource & source,const FileSectionInfo & section_info,const ProfileLoadFilterFn & filter_fn,dchecked_vector<ProfileIndexType> * dex_profile_index_remap,std::string * error)1603 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadDexFilesSection(
1604     ProfileSource& source,
1605     const FileSectionInfo& section_info,
1606     const ProfileLoadFilterFn& filter_fn,
1607     /*out*/ dchecked_vector<ProfileIndexType>* dex_profile_index_remap,
1608     /*out*/ std::string* error) {
1609   DCHECK(section_info.GetType() == FileSectionType::kDexFiles);
1610   SafeBuffer buffer;
1611   ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1612   if (status != ProfileLoadStatus::kSuccess) {
1613     return status;
1614   }
1615 
1616   ProfileIndexType num_dex_files;
1617   if (!buffer.ReadUintAndAdvance(&num_dex_files)) {
1618     *error = "Error reading number of dex files.";
1619     return ProfileLoadStatus::kBadData;
1620   }
1621   if (num_dex_files >= MaxProfileIndex()) {
1622     *error = "Too many dex files.";
1623     return ProfileLoadStatus::kBadData;
1624   }
1625 
1626   DCHECK(dex_profile_index_remap->empty());
1627   for (ProfileIndexType i = 0u; i != num_dex_files; ++i) {
1628     uint32_t checksum, num_type_ids, num_method_ids;
1629     if (!buffer.ReadUintAndAdvance(&checksum) ||
1630         !buffer.ReadUintAndAdvance(&num_type_ids) ||
1631         !buffer.ReadUintAndAdvance(&num_method_ids)) {
1632       *error = "Error reading dex file data.";
1633       return ProfileLoadStatus::kBadData;
1634     }
1635     std::string_view profile_key_view;
1636     if (!buffer.ReadStringAndAdvance(&profile_key_view)) {
1637       *error += "Missing terminating null character for profile key.";
1638       return ProfileLoadStatus::kBadData;
1639     }
1640     if (profile_key_view.size() == 0u || profile_key_view.size() > kMaxDexFileKeyLength) {
1641       *error = "ProfileKey has an invalid size: " + std::to_string(profile_key_view.size());
1642       return ProfileLoadStatus::kBadData;
1643     }
1644     std::string profile_key(profile_key_view);
1645     if (!filter_fn(profile_key, checksum)) {
1646       // Do not load data for this key. Store invalid index to `dex_profile_index_remap`.
1647       VLOG(compiler) << "Profile: Filtered out " << profile_key << " 0x" << std::hex << checksum;
1648       dex_profile_index_remap->push_back(MaxProfileIndex());
1649       continue;
1650     }
1651     DexFileData* data = GetOrAddDexFileData(profile_key, checksum, num_type_ids, num_method_ids);
1652     if (data == nullptr) {
1653       if (UNLIKELY(profile_key_map_.size() == MaxProfileIndex()) &&
1654           profile_key_map_.find(profile_key) == profile_key_map_.end()) {
1655         *error = "Too many dex files.";
1656       } else {
1657         *error = "Checksum, NumTypeIds, or NumMethodIds mismatch for " + profile_key;
1658       }
1659       return ProfileLoadStatus::kBadData;
1660     }
1661     dex_profile_index_remap->push_back(data->profile_index);
1662   }
1663   if (buffer.GetAvailableBytes() != 0u) {
1664     *error = "Unexpected data at end of dex files section.";
1665     return ProfileLoadStatus::kBadData;
1666   }
1667   return ProfileLoadStatus::kSuccess;
1668 }
1669 
ReadExtraDescriptorsSection(ProfileSource & source,const FileSectionInfo & section_info,dchecked_vector<ExtraDescriptorIndex> * extra_descriptors_remap,std::string * error)1670 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadExtraDescriptorsSection(
1671     ProfileSource& source,
1672     const FileSectionInfo& section_info,
1673     /*out*/ dchecked_vector<ExtraDescriptorIndex>* extra_descriptors_remap,
1674     /*out*/ std::string* error) {
1675   DCHECK(section_info.GetType() == FileSectionType::kExtraDescriptors);
1676   SafeBuffer buffer;
1677   ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1678   if (status != ProfileLoadStatus::kSuccess) {
1679     return status;
1680   }
1681 
1682   uint16_t num_extra_descriptors;
1683   if (!buffer.ReadUintAndAdvance(&num_extra_descriptors)) {
1684     *error = "Error reading number of extra descriptors.";
1685     return ProfileLoadStatus::kBadData;
1686   }
1687 
1688   // Note: We allow multiple extra descriptors sections in a single profile file
1689   // but that can lead to `kMergeError` if there are too many extra descriptors.
1690   // Other sections can reference only extra descriptors from preceding sections.
1691   extra_descriptors_remap->reserve(
1692       std::min<size_t>(extra_descriptors_remap->size() + num_extra_descriptors,
1693                        std::numeric_limits<uint16_t>::max()));
1694   for (uint16_t i = 0; i != num_extra_descriptors; ++i) {
1695     std::string_view extra_descriptor;
1696     if (!buffer.ReadStringAndAdvance(&extra_descriptor)) {
1697       *error += "Missing terminating null character for extra descriptor.";
1698       return ProfileLoadStatus::kBadData;
1699     }
1700     if (!IsValidDescriptor(std::string(extra_descriptor).c_str())) {
1701       *error += "Invalid extra descriptor.";
1702       return ProfileLoadStatus::kBadData;
1703     }
1704     // Try to match an existing extra descriptor.
1705     auto it = extra_descriptors_indexes_.find(extra_descriptor);
1706     if (it != extra_descriptors_indexes_.end()) {
1707       extra_descriptors_remap->push_back(*it);
1708       continue;
1709     }
1710     // Try to insert a new extra descriptor.
1711     ExtraDescriptorIndex extra_descriptor_index = AddExtraDescriptor(extra_descriptor);
1712     if (extra_descriptor_index == kMaxExtraDescriptors) {
1713       *error = "Too many extra descriptors.";
1714       return ProfileLoadStatus::kMergeError;
1715     }
1716     extra_descriptors_remap->push_back(extra_descriptor_index);
1717   }
1718   return ProfileLoadStatus::kSuccess;
1719 }
1720 
ReadClassesSection(ProfileSource & source,const FileSectionInfo & section_info,const dchecked_vector<ProfileIndexType> & dex_profile_index_remap,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)1721 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadClassesSection(
1722     ProfileSource& source,
1723     const FileSectionInfo& section_info,
1724     const dchecked_vector<ProfileIndexType>& dex_profile_index_remap,
1725     const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
1726     /*out*/ std::string* error) {
1727   DCHECK(section_info.GetType() == FileSectionType::kClasses);
1728   SafeBuffer buffer;
1729   ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1730   if (status != ProfileLoadStatus::kSuccess) {
1731     return status;
1732   }
1733 
1734   while (buffer.GetAvailableBytes() != 0u) {
1735     ProfileIndexType profile_index;
1736     if (!buffer.ReadUintAndAdvance(&profile_index)) {
1737       *error = "Error profile index in classes section.";
1738       return ProfileLoadStatus::kBadData;
1739     }
1740     if (profile_index >= dex_profile_index_remap.size()) {
1741       *error = "Invalid profile index in classes section.";
1742       return ProfileLoadStatus::kBadData;
1743     }
1744     profile_index = dex_profile_index_remap[profile_index];
1745     if (profile_index == MaxProfileIndex()) {
1746       status = DexFileData::SkipClasses(buffer, error);
1747     } else {
1748       status = info_[profile_index]->ReadClasses(buffer, extra_descriptors_remap, error);
1749     }
1750     if (status != ProfileLoadStatus::kSuccess) {
1751       return status;
1752     }
1753   }
1754   return ProfileLoadStatus::kSuccess;
1755 }
1756 
ReadMethodsSection(ProfileSource & source,const FileSectionInfo & section_info,const dchecked_vector<ProfileIndexType> & dex_profile_index_remap,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)1757 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::ReadMethodsSection(
1758     ProfileSource& source,
1759     const FileSectionInfo& section_info,
1760     const dchecked_vector<ProfileIndexType>& dex_profile_index_remap,
1761     const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
1762     /*out*/ std::string* error) {
1763   DCHECK(section_info.GetType() == FileSectionType::kMethods);
1764   SafeBuffer buffer;
1765   ProfileLoadStatus status = ReadSectionData(source, section_info, &buffer, error);
1766   if (status != ProfileLoadStatus::kSuccess) {
1767     return status;
1768   }
1769 
1770   while (buffer.GetAvailableBytes() != 0u) {
1771     ProfileIndexType profile_index;
1772     if (!buffer.ReadUintAndAdvance(&profile_index)) {
1773       *error = "Error profile index in methods section.";
1774       return ProfileLoadStatus::kBadData;
1775     }
1776     if (profile_index >= dex_profile_index_remap.size()) {
1777       *error = "Invalid profile index in methods section.";
1778       return ProfileLoadStatus::kBadData;
1779     }
1780     profile_index = dex_profile_index_remap[profile_index];
1781     if (profile_index == MaxProfileIndex()) {
1782       status = DexFileData::SkipMethods(buffer, error);
1783     } else {
1784       status = info_[profile_index]->ReadMethods(buffer, extra_descriptors_remap, error);
1785     }
1786     if (status != ProfileLoadStatus::kSuccess) {
1787       return status;
1788     }
1789   }
1790   return ProfileLoadStatus::kSuccess;
1791 }
1792 
1793 // TODO(calin): fail fast if the dex checksums don't match.
LoadInternal(int32_t fd,std::string * error,bool merge_classes,const ProfileLoadFilterFn & filter_fn)1794 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::LoadInternal(
1795     int32_t fd,
1796     std::string* error,
1797     bool merge_classes,
1798     const ProfileLoadFilterFn& filter_fn) {
1799   ScopedTrace trace(__PRETTY_FUNCTION__);
1800   DCHECK_GE(fd, 0);
1801 
1802   std::unique_ptr<ProfileSource> source;
1803   ProfileLoadStatus status = OpenSource(fd, &source, error);
1804   if (status != ProfileLoadStatus::kSuccess) {
1805     return status;
1806   }
1807 
1808   // We allow empty profile files.
1809   // Profiles may be created by ActivityManager or installd before we manage to
1810   // process them in the runtime or profman.
1811   if (source->HasEmptyContent()) {
1812     return ProfileLoadStatus::kSuccess;
1813   }
1814 
1815   // Read file header.
1816   FileHeader header;
1817   status = source->Read(&header, sizeof(FileHeader), "ReadProfileHeader", error);
1818   if (status != ProfileLoadStatus::kSuccess) {
1819     return status;
1820   }
1821   if (!header.IsValid()) {
1822     return header.InvalidHeaderMessage(error);
1823   }
1824   if (memcmp(header.GetVersion(), version_, kProfileVersionSize) != 0) {
1825     *error = IsForBootImage() ? "Expected boot profile, got app profile."
1826                               : "Expected app profile, got boot profile.";
1827     return ProfileLoadStatus::kVersionMismatch;
1828   }
1829 
1830   // Check if there are too many section infos.
1831   uint32_t section_count = header.GetFileSectionCount();
1832   uint32_t uncompressed_data_size = sizeof(FileHeader) + section_count * sizeof(FileSectionInfo);
1833   if (uncompressed_data_size > GetSizeErrorThresholdBytes()) {
1834     LOG(WARNING) << "Profile data size exceeds " << GetSizeErrorThresholdBytes()
1835                << " bytes. It has " << uncompressed_data_size << " bytes.";
1836     return ProfileLoadStatus::kBadData;
1837   }
1838 
1839   // Read section infos.
1840   dchecked_vector<FileSectionInfo> section_infos(section_count);
1841   status = source->Read(
1842       section_infos.data(), section_count * sizeof(FileSectionInfo), "ReadSectionInfos", error);
1843   if (status != ProfileLoadStatus::kSuccess) {
1844     return status;
1845   }
1846 
1847   // Finish uncompressed data size calculation.
1848   for (const FileSectionInfo& section_info : section_infos) {
1849     uint32_t mem_size = section_info.GetMemSize();
1850     if (UNLIKELY(mem_size > std::numeric_limits<uint32_t>::max() - uncompressed_data_size)) {
1851       *error = "Total memory size overflow.";
1852       return ProfileLoadStatus::kBadData;
1853     }
1854     uncompressed_data_size += mem_size;
1855   }
1856 
1857   // Allow large profiles for non target builds for the case where we are merging many profiles
1858   // to generate a boot image profile.
1859   if (uncompressed_data_size > GetSizeErrorThresholdBytes()) {
1860     LOG(WARNING) << "Profile data size exceeds "
1861                << GetSizeErrorThresholdBytes()
1862                << " bytes. It has " << uncompressed_data_size << " bytes.";
1863     return ProfileLoadStatus::kBadData;
1864   }
1865   if (uncompressed_data_size > GetSizeWarningThresholdBytes()) {
1866     LOG(WARNING) << "Profile data size exceeds "
1867                  << GetSizeWarningThresholdBytes()
1868                  << " bytes. It has " << uncompressed_data_size << " bytes.";
1869   }
1870 
1871   // Process the mandatory dex files section.
1872   DCHECK_NE(section_count, 0u);  // Checked by `header.IsValid()` above.
1873   const FileSectionInfo& dex_files_section_info = section_infos[0];
1874   if (dex_files_section_info.GetType() != FileSectionType::kDexFiles) {
1875     *error = "First section is not dex files section.";
1876     return ProfileLoadStatus::kBadData;
1877   }
1878   dchecked_vector<ProfileIndexType> dex_profile_index_remap;
1879   status = ReadDexFilesSection(
1880       *source, dex_files_section_info, filter_fn, &dex_profile_index_remap, error);
1881   if (status != ProfileLoadStatus::kSuccess) {
1882     DCHECK(!error->empty());
1883     return status;
1884   }
1885 
1886   // Process all other sections.
1887   dchecked_vector<ExtraDescriptorIndex> extra_descriptors_remap;
1888   for (uint32_t i = 1u; i != section_count; ++i) {
1889     const FileSectionInfo& section_info = section_infos[i];
1890     DCHECK(status == ProfileLoadStatus::kSuccess);
1891     switch (section_info.GetType()) {
1892       case FileSectionType::kDexFiles:
1893         *error = "Unsupported additional dex files section.";
1894         status = ProfileLoadStatus::kBadData;
1895         break;
1896       case FileSectionType::kExtraDescriptors:
1897         status = ReadExtraDescriptorsSection(
1898             *source, section_info, &extra_descriptors_remap, error);
1899         break;
1900       case FileSectionType::kClasses:
1901         // Skip if all dex files were filtered out.
1902         if (!info_.empty() && merge_classes) {
1903           status = ReadClassesSection(
1904               *source, section_info, dex_profile_index_remap, extra_descriptors_remap, error);
1905         }
1906         break;
1907       case FileSectionType::kMethods:
1908         // Skip if all dex files were filtered out.
1909         if (!info_.empty()) {
1910           status = ReadMethodsSection(
1911               *source, section_info, dex_profile_index_remap, extra_descriptors_remap, error);
1912         }
1913         break;
1914       case FileSectionType::kAggregationCounts:
1915         // This section is only used on server side.
1916         break;
1917       default:
1918         // Unknown section. Skip it. New versions of ART are allowed
1919         // to add sections that shall be ignored by old versions.
1920         break;
1921     }
1922     if (status != ProfileLoadStatus::kSuccess) {
1923       DCHECK(!error->empty());
1924       return status;
1925     }
1926   }
1927 
1928   return ProfileLoadStatus::kSuccess;
1929 }
1930 
MergeWith(const ProfileCompilationInfo & other,bool merge_classes)1931 bool ProfileCompilationInfo::MergeWith(const ProfileCompilationInfo& other,
1932                                        bool merge_classes) {
1933   if (!SameVersion(other)) {
1934     LOG(WARNING) << "Cannot merge different profile versions";
1935     return false;
1936   }
1937 
1938   // First verify that all checksums match. This will avoid adding garbage to
1939   // the current profile info.
1940   // Note that the number of elements should be very small, so this should not
1941   // be a performance issue.
1942   for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1943     // verify_checksum is false because we want to differentiate between a missing dex data and
1944     // a mismatched checksum.
1945     const DexFileData* dex_data = FindDexData(other_dex_data->profile_key,
1946                                               /* checksum= */ 0u,
1947                                               /* verify_checksum= */ false);
1948     if ((dex_data != nullptr) && (dex_data->checksum != other_dex_data->checksum)) {
1949       LOG(WARNING) << "Checksum mismatch for dex " << other_dex_data->profile_key;
1950       return false;
1951     }
1952   }
1953   // All checksums match. Import the data.
1954 
1955   // The other profile might have a different indexing of dex files.
1956   // That is because each dex files gets a 'dex_profile_index' on a first come first served basis.
1957   // That means that the order in with the methods are added to the profile matters for the
1958   // actual indices.
1959   // The reason we cannot rely on the actual multidex index is that a single profile may store
1960   // data from multiple splits. This means that a profile may contain a classes2.dex from split-A
1961   // and one from split-B.
1962 
1963   // First, build a mapping from other_dex_profile_index to this_dex_profile_index.
1964   dchecked_vector<ProfileIndexType> dex_profile_index_remap;
1965   dex_profile_index_remap.reserve(other.info_.size());
1966   for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1967     const DexFileData* dex_data = GetOrAddDexFileData(other_dex_data->profile_key,
1968                                                       other_dex_data->checksum,
1969                                                       other_dex_data->num_type_ids,
1970                                                       other_dex_data->num_method_ids);
1971     if (dex_data == nullptr) {
1972       // Could happen if we exceed the number of allowed dex files or there is
1973       // a mismatch in `num_type_ids` or `num_method_ids`.
1974       return false;
1975     }
1976     DCHECK_EQ(other_dex_data->profile_index, dex_profile_index_remap.size());
1977     dex_profile_index_remap.push_back(dex_data->profile_index);
1978   }
1979 
1980   // Then merge extra descriptors.
1981   dchecked_vector<ExtraDescriptorIndex> extra_descriptors_remap;
1982   extra_descriptors_remap.reserve(other.extra_descriptors_.size());
1983   for (const std::string& other_extra_descriptor : other.extra_descriptors_) {
1984     auto it = extra_descriptors_indexes_.find(std::string_view(other_extra_descriptor));
1985     if (it != extra_descriptors_indexes_.end()) {
1986       extra_descriptors_remap.push_back(*it);
1987     } else {
1988       ExtraDescriptorIndex extra_descriptor_index = AddExtraDescriptor(other_extra_descriptor);
1989       if (extra_descriptor_index == kMaxExtraDescriptors) {
1990         // Too many extra descriptors.
1991         return false;
1992       }
1993       extra_descriptors_remap.push_back(extra_descriptor_index);
1994     }
1995   }
1996 
1997   // Merge the actual profile data.
1998   for (const std::unique_ptr<DexFileData>& other_dex_data : other.info_) {
1999     DexFileData* dex_data = info_[dex_profile_index_remap[other_dex_data->profile_index]].get();
2000     DCHECK_EQ(dex_data, FindDexData(other_dex_data->profile_key, other_dex_data->checksum));
2001 
2002     // Merge the classes.
2003     uint32_t num_type_ids = dex_data->num_type_ids;
2004     DCHECK_EQ(num_type_ids, other_dex_data->num_type_ids);
2005     if (merge_classes) {
2006       // Classes are ordered by the `TypeIndex`, so we have the classes with a `TypeId`
2007       // in the dex file first, followed by classes using extra descriptors.
2008       auto it = other_dex_data->class_set.lower_bound(dex::TypeIndex(num_type_ids));
2009       dex_data->class_set.insert(other_dex_data->class_set.begin(), it);
2010       for (auto end = other_dex_data->class_set.end(); it != end; ++it) {
2011         ExtraDescriptorIndex new_extra_descriptor_index =
2012             extra_descriptors_remap[it->index_ - num_type_ids];
2013         if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2014           // Cannot represent the type with new extra descriptor index.
2015           return false;
2016         }
2017         dex_data->class_set.insert(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
2018       }
2019     }
2020 
2021     // Merge the methods and the inline caches.
2022     for (const auto& other_method_it : other_dex_data->method_map) {
2023       uint16_t other_method_index = other_method_it.first;
2024       InlineCacheMap* inline_cache = dex_data->FindOrAddHotMethod(other_method_index);
2025       if (inline_cache == nullptr) {
2026         return false;
2027       }
2028       const auto& other_inline_cache = other_method_it.second;
2029       for (const auto& other_ic_it : other_inline_cache) {
2030         uint16_t other_dex_pc = other_ic_it.first;
2031         const ArenaSet<dex::TypeIndex>& other_class_set = other_ic_it.second.classes;
2032         DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, other_dex_pc);
2033         if (other_ic_it.second.is_missing_types) {
2034           dex_pc_data->SetIsMissingTypes();
2035         } else if (other_ic_it.second.is_megamorphic) {
2036           dex_pc_data->SetIsMegamorphic();
2037         } else {
2038           for (dex::TypeIndex type_index : other_class_set) {
2039             if (type_index.index_ >= num_type_ids) {
2040               ExtraDescriptorIndex new_extra_descriptor_index =
2041                   extra_descriptors_remap[type_index.index_ - num_type_ids];
2042               if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2043                 // Cannot represent the type with new extra descriptor index.
2044                 return false;
2045               }
2046               type_index = dex::TypeIndex(num_type_ids + new_extra_descriptor_index);
2047             }
2048             dex_pc_data->AddClass(type_index);
2049           }
2050         }
2051       }
2052     }
2053 
2054     // Merge the method bitmaps.
2055     dex_data->MergeBitmap(*other_dex_data);
2056   }
2057 
2058   return true;
2059 }
2060 
GetMethodHotness(const MethodReference & method_ref,const ProfileSampleAnnotation & annotation) const2061 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::GetMethodHotness(
2062     const MethodReference& method_ref,
2063     const ProfileSampleAnnotation& annotation) const {
2064   const DexFileData* dex_data = FindDexDataUsingAnnotations(method_ref.dex_file, annotation);
2065   return dex_data != nullptr
2066       ? dex_data->GetHotnessInfo(method_ref.index)
2067       : MethodHotness();
2068 }
2069 
ContainsClass(const DexFile & dex_file,dex::TypeIndex type_idx,const ProfileSampleAnnotation & annotation) const2070 bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file,
2071                                            dex::TypeIndex type_idx,
2072                                            const ProfileSampleAnnotation& annotation) const {
2073   const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2074   return (dex_data != nullptr) && dex_data->ContainsClass(type_idx);
2075 }
2076 
GetNumberOfMethods() const2077 uint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
2078   uint32_t total = 0;
2079   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2080     total += dex_data->method_map.size();
2081   }
2082   return total;
2083 }
2084 
GetNumberOfResolvedClasses() const2085 uint32_t ProfileCompilationInfo::GetNumberOfResolvedClasses() const {
2086   uint32_t total = 0;
2087   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2088     total += dex_data->class_set.size();
2089   }
2090   return total;
2091 }
2092 
DumpInfo(const std::vector<const DexFile * > & dex_files,bool print_full_dex_location) const2093 std::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>& dex_files,
2094                                              bool print_full_dex_location) const {
2095   std::ostringstream os;
2096 
2097   os << "ProfileInfo [";
2098 
2099   for (size_t k = 0; k <  kProfileVersionSize - 1; k++) {
2100     // Iterate to 'kProfileVersionSize - 1' because the version_ ends with '\0'
2101     // which we don't want to print.
2102     os << static_cast<char>(version_[k]);
2103   }
2104   os << "]\n";
2105 
2106   if (info_.empty()) {
2107     os << "-empty-";
2108     return os.str();
2109   }
2110 
2111   if (!extra_descriptors_.empty()) {
2112     os << "\nextra descriptors:";
2113     for (const std::string& str : extra_descriptors_) {
2114       os << "\n\t" << str;
2115     }
2116     os << "\n";
2117   }
2118 
2119   const std::string kFirstDexFileKeySubstitute = "!classes.dex";
2120 
2121   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2122     os << "\n";
2123     if (print_full_dex_location) {
2124       os << dex_data->profile_key;
2125     } else {
2126       // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
2127       std::string multidex_suffix = DexFileLoader::GetMultiDexSuffix(
2128           GetBaseKeyFromAugmentedKey(dex_data->profile_key));
2129       os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
2130     }
2131     os << " [index=" << static_cast<uint32_t>(dex_data->profile_index) << "]";
2132     os << " [checksum=" << std::hex << dex_data->checksum << "]" << std::dec;
2133     os << " [num_type_ids=" << dex_data->num_type_ids << "]";
2134     os << " [num_method_ids=" << dex_data->num_method_ids << "]";
2135     const DexFile* dex_file = nullptr;
2136     for (const DexFile* current : dex_files) {
2137       if (GetBaseKeyViewFromAugmentedKey(dex_data->profile_key) ==
2138           GetProfileDexFileBaseKeyView(current->GetLocation()) &&
2139           ChecksumMatch(dex_data->checksum, current->GetLocationChecksum())) {
2140         dex_file = current;
2141         break;
2142       }
2143     }
2144     os << "\n\thot methods: ";
2145     for (const auto& method_it : dex_data->method_map) {
2146       if (dex_file != nullptr) {
2147         os << "\n\t\t" << dex_file->PrettyMethod(method_it.first, true);
2148       } else {
2149         os << method_it.first;
2150       }
2151 
2152       os << "[";
2153       for (const auto& inline_cache_it : method_it.second) {
2154         os << "{" << std::hex << inline_cache_it.first << std::dec << ":";
2155         if (inline_cache_it.second.is_missing_types) {
2156           os << "MT";
2157         } else if (inline_cache_it.second.is_megamorphic) {
2158           os << "MM";
2159         } else {
2160           const char* separator = "";
2161           for (dex::TypeIndex type_index : inline_cache_it.second.classes) {
2162             os << separator << type_index.index_;
2163             separator = ",";
2164           }
2165         }
2166         os << "}";
2167       }
2168       os << "], ";
2169     }
2170     bool startup = true;
2171     while (true) {
2172       os << "\n\t" << (startup ? "startup methods: " : "post startup methods: ");
2173       for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2174         MethodHotness hotness_info(dex_data->GetHotnessInfo(method_idx));
2175         if (startup ? hotness_info.IsStartup() : hotness_info.IsPostStartup()) {
2176           if (dex_file != nullptr) {
2177             os << "\n\t\t" << dex_file->PrettyMethod(method_idx, true);
2178           } else {
2179             os << method_idx << ", ";
2180           }
2181         }
2182       }
2183       if (startup == false) {
2184         break;
2185       }
2186       startup = false;
2187     }
2188     os << "\n\tclasses: ";
2189     for (dex::TypeIndex type_index : dex_data->class_set) {
2190       if (dex_file != nullptr) {
2191         os << "\n\t\t" << PrettyDescriptor(GetTypeDescriptor(dex_file, type_index));
2192       } else {
2193         os << type_index.index_ << ",";
2194       }
2195     }
2196   }
2197   return os.str();
2198 }
2199 
GetClassesAndMethods(const DexFile & dex_file,std::set<dex::TypeIndex> * class_set,std::set<uint16_t> * hot_method_set,std::set<uint16_t> * startup_method_set,std::set<uint16_t> * post_startup_method_method_set,const ProfileSampleAnnotation & annotation) const2200 bool ProfileCompilationInfo::GetClassesAndMethods(
2201     const DexFile& dex_file,
2202     /*out*/std::set<dex::TypeIndex>* class_set,
2203     /*out*/std::set<uint16_t>* hot_method_set,
2204     /*out*/std::set<uint16_t>* startup_method_set,
2205     /*out*/std::set<uint16_t>* post_startup_method_method_set,
2206     const ProfileSampleAnnotation& annotation) const {
2207   std::set<std::string> ret;
2208   const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2209   if (dex_data == nullptr) {
2210     return false;
2211   }
2212   for (const auto& it : dex_data->method_map) {
2213     hot_method_set->insert(it.first);
2214   }
2215   for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
2216     MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
2217     if (hotness.IsStartup()) {
2218       startup_method_set->insert(method_idx);
2219     }
2220     if (hotness.IsPostStartup()) {
2221       post_startup_method_method_set->insert(method_idx);
2222     }
2223   }
2224   for (const dex::TypeIndex& type_index : dex_data->class_set) {
2225     class_set->insert(type_index);
2226   }
2227   return true;
2228 }
2229 
GetClasses(const DexFile & dex_file,const ProfileSampleAnnotation & annotation) const2230 const ArenaSet<dex::TypeIndex>* ProfileCompilationInfo::GetClasses(
2231     const DexFile& dex_file,
2232     const ProfileSampleAnnotation& annotation) const {
2233   const DexFileData* dex_data = FindDexDataUsingAnnotations(&dex_file, annotation);
2234   if (dex_data == nullptr) {
2235     return nullptr;
2236   }
2237   return &dex_data->class_set;
2238 }
2239 
SameVersion(const ProfileCompilationInfo & other) const2240 bool ProfileCompilationInfo::SameVersion(const ProfileCompilationInfo& other) const {
2241   return memcmp(version_, other.version_, kProfileVersionSize) == 0;
2242 }
2243 
Equals(const ProfileCompilationInfo & other)2244 bool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
2245   // No need to compare profile_key_map_. That's only a cache for fast search.
2246   // All the information is already in the info_ vector.
2247   if (!SameVersion(other)) {
2248     return false;
2249   }
2250   if (info_.size() != other.info_.size()) {
2251     return false;
2252   }
2253   for (size_t i = 0; i < info_.size(); i++) {
2254     const DexFileData& dex_data = *info_[i];
2255     const DexFileData& other_dex_data = *other.info_[i];
2256     if (!(dex_data == other_dex_data)) {
2257       return false;
2258     }
2259   }
2260 
2261   return true;
2262 }
2263 
2264 // Naive implementation to generate a random profile file suitable for testing.
GenerateTestProfile(int fd,uint16_t number_of_dex_files,uint16_t method_percentage,uint16_t class_percentage,uint32_t random_seed)2265 bool ProfileCompilationInfo::GenerateTestProfile(int fd,
2266                                                  uint16_t number_of_dex_files,
2267                                                  uint16_t method_percentage,
2268                                                  uint16_t class_percentage,
2269                                                  uint32_t random_seed) {
2270   const std::string base_dex_location = "base.apk";
2271   ProfileCompilationInfo info;
2272   // The limits are defined by the dex specification.
2273   const uint16_t max_methods = std::numeric_limits<uint16_t>::max();
2274   const uint16_t max_classes = std::numeric_limits<uint16_t>::max();
2275   uint16_t number_of_methods = max_methods * method_percentage / 100;
2276   uint16_t number_of_classes = max_classes * class_percentage / 100;
2277 
2278   std::srand(random_seed);
2279 
2280   // Make sure we generate more samples with a low index value.
2281   // This makes it more likely to hit valid method/class indices in small apps.
2282   const uint16_t kFavorFirstN = 10000;
2283   const uint16_t kFavorSplit = 2;
2284 
2285   for (uint16_t i = 0; i < number_of_dex_files; i++) {
2286     std::string dex_location = DexFileLoader::GetMultiDexLocation(i, base_dex_location.c_str());
2287     std::string profile_key = info.GetProfileDexFileBaseKey(dex_location);
2288 
2289     DexFileData* const data =
2290         info.GetOrAddDexFileData(profile_key, /*checksum=*/ 0, max_classes, max_methods);
2291     for (uint16_t m = 0; m < number_of_methods; m++) {
2292       uint16_t method_idx = rand() % max_methods;
2293       if (m < (number_of_methods / kFavorSplit)) {
2294         method_idx %= kFavorFirstN;
2295       }
2296       // Alternate between startup and post startup.
2297       uint32_t flags = MethodHotness::kFlagHot;
2298       flags |= ((m & 1) != 0) ? MethodHotness::kFlagPostStartup : MethodHotness::kFlagStartup;
2299       data->AddMethod(static_cast<MethodHotness::Flag>(flags), method_idx);
2300     }
2301 
2302     for (uint16_t c = 0; c < number_of_classes; c++) {
2303       uint16_t type_idx = rand() % max_classes;
2304       if (c < (number_of_classes / kFavorSplit)) {
2305         type_idx %= kFavorFirstN;
2306       }
2307       data->class_set.insert(dex::TypeIndex(type_idx));
2308     }
2309   }
2310   return info.Save(fd);
2311 }
2312 
2313 // Naive implementation to generate a random profile file suitable for testing.
2314 // Description of random selection:
2315 // * Select a random starting point S.
2316 // * For every index i, add (S+i) % (N - total number of methods/classes) to profile with the
2317 //   probably of 1/(N - i - number of methods/classes needed to add in profile).
GenerateTestProfile(int fd,std::vector<std::unique_ptr<const DexFile>> & dex_files,uint16_t method_percentage,uint16_t class_percentage,uint32_t random_seed)2318 bool ProfileCompilationInfo::GenerateTestProfile(
2319     int fd,
2320     std::vector<std::unique_ptr<const DexFile>>& dex_files,
2321     uint16_t method_percentage,
2322     uint16_t class_percentage,
2323     uint32_t random_seed) {
2324   ProfileCompilationInfo info;
2325   std::default_random_engine rng(random_seed);
2326   auto create_shuffled_range = [&rng](uint32_t take, uint32_t out_of) {
2327     CHECK_LE(take, out_of);
2328     std::vector<uint32_t> vec(out_of);
2329     std::iota(vec.begin(), vec.end(), 0u);
2330     std::shuffle(vec.begin(), vec.end(), rng);
2331     vec.erase(vec.begin() + take, vec.end());
2332     std::sort(vec.begin(), vec.end());
2333     return vec;
2334   };
2335   for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
2336     const std::string& dex_location = dex_file->GetLocation();
2337     std::string profile_key = info.GetProfileDexFileBaseKey(dex_location);
2338     uint32_t checksum = dex_file->GetLocationChecksum();
2339 
2340     uint32_t number_of_classes = dex_file->NumClassDefs();
2341     uint32_t classes_required_in_profile = (number_of_classes * class_percentage) / 100;
2342 
2343     DexFileData* const data = info.GetOrAddDexFileData(
2344           profile_key, checksum, dex_file->NumTypeIds(), dex_file->NumMethodIds());
2345     for (uint32_t class_index : create_shuffled_range(classes_required_in_profile,
2346                                                       number_of_classes)) {
2347       data->class_set.insert(dex_file->GetClassDef(class_index).class_idx_);
2348     }
2349 
2350     uint32_t number_of_methods = dex_file->NumMethodIds();
2351     uint32_t methods_required_in_profile = (number_of_methods * method_percentage) / 100;
2352     for (uint32_t method_index : create_shuffled_range(methods_required_in_profile,
2353                                                        number_of_methods)) {
2354       // Alternate between startup and post startup.
2355       uint32_t flags = MethodHotness::kFlagHot;
2356       flags |= ((method_index & 1) != 0)
2357                    ? MethodHotness::kFlagPostStartup
2358                    : MethodHotness::kFlagStartup;
2359       data->AddMethod(static_cast<MethodHotness::Flag>(flags), method_index);
2360     }
2361   }
2362   return info.Save(fd);
2363 }
2364 
IsEmpty() const2365 bool ProfileCompilationInfo::IsEmpty() const {
2366   DCHECK_EQ(info_.size(), profile_key_map_.size());
2367   // Note that this doesn't look at the bitmap region, so we will return true
2368   // when the profile contains only non-hot methods. This is generally ok
2369   // as for speed-profile to be useful we do need hot methods and resolved classes.
2370   return GetNumberOfMethods() == 0 && GetNumberOfResolvedClasses() == 0;
2371 }
2372 
2373 ProfileCompilationInfo::InlineCacheMap*
FindOrAddHotMethod(uint16_t method_index)2374 ProfileCompilationInfo::DexFileData::FindOrAddHotMethod(uint16_t method_index) {
2375   if (method_index >= num_method_ids) {
2376     LOG(ERROR) << "Invalid method index " << method_index << ". num_method_ids=" << num_method_ids;
2377     return nullptr;
2378   }
2379   return &(method_map.FindOrAdd(
2380       method_index,
2381       InlineCacheMap(std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile)))->second);
2382 }
2383 
2384 // Mark a method as executed at least once.
AddMethod(MethodHotness::Flag flags,size_t index)2385 bool ProfileCompilationInfo::DexFileData::AddMethod(MethodHotness::Flag flags, size_t index) {
2386   if (index >= num_method_ids || index > kMaxSupportedMethodIndex) {
2387     LOG(ERROR) << "Invalid method index " << index << ". num_method_ids=" << num_method_ids
2388         << ", max: " << kMaxSupportedMethodIndex;
2389     return false;
2390   }
2391 
2392   SetMethodHotness(index, flags);
2393 
2394   if ((flags & MethodHotness::kFlagHot) != 0) {
2395     ProfileCompilationInfo::InlineCacheMap* result = FindOrAddHotMethod(index);
2396     DCHECK(result != nullptr);
2397   }
2398   return true;
2399 }
2400 
SetMethodHotness(size_t index,MethodHotness::Flag flags)2401 void ProfileCompilationInfo::DexFileData::SetMethodHotness(size_t index,
2402                                                            MethodHotness::Flag flags) {
2403   DCHECK_LT(index, num_method_ids);
2404   ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2405     if ((flags & flag) != 0) {
2406       method_bitmap.StoreBit(MethodFlagBitmapIndex(
2407           static_cast<MethodHotness::Flag>(flag), index), /*value=*/ true);
2408     }
2409     return true;
2410   });
2411 }
2412 
GetHotnessInfo(uint32_t dex_method_index) const2413 ProfileCompilationInfo::MethodHotness ProfileCompilationInfo::DexFileData::GetHotnessInfo(
2414     uint32_t dex_method_index) const {
2415   MethodHotness ret;
2416   ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2417     if (method_bitmap.LoadBit(MethodFlagBitmapIndex(
2418             static_cast<MethodHotness::Flag>(flag), dex_method_index))) {
2419       ret.AddFlag(static_cast<MethodHotness::Flag>(flag));
2420     }
2421     return true;
2422   });
2423   auto it = method_map.find(dex_method_index);
2424   if (it != method_map.end()) {
2425     ret.SetInlineCacheMap(&it->second);
2426     ret.AddFlag(MethodHotness::kFlagHot);
2427   }
2428   return ret;
2429 }
2430 
2431 // To simplify the implementation we use the MethodHotness flag values as indexes into the internal
2432 // bitmap representation. As such, they should never change unless the profile version is updated
2433 // and the implementation changed accordingly.
2434 static_assert(ProfileCompilationInfo::MethodHotness::kFlagFirst == 1 << 0);
2435 static_assert(ProfileCompilationInfo::MethodHotness::kFlagHot == 1 << 0);
2436 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartup == 1 << 1);
2437 static_assert(ProfileCompilationInfo::MethodHotness::kFlagPostStartup == 1 << 2);
2438 static_assert(ProfileCompilationInfo::MethodHotness::kFlagLastRegular == 1 << 2);
2439 static_assert(ProfileCompilationInfo::MethodHotness::kFlag32bit == 1 << 3);
2440 static_assert(ProfileCompilationInfo::MethodHotness::kFlag64bit == 1 << 4);
2441 static_assert(ProfileCompilationInfo::MethodHotness::kFlagSensitiveThread == 1 << 5);
2442 static_assert(ProfileCompilationInfo::MethodHotness::kFlagAmStartup == 1 << 6);
2443 static_assert(ProfileCompilationInfo::MethodHotness::kFlagAmPostStartup == 1 << 7);
2444 static_assert(ProfileCompilationInfo::MethodHotness::kFlagBoot == 1 << 8);
2445 static_assert(ProfileCompilationInfo::MethodHotness::kFlagPostBoot == 1 << 9);
2446 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartupBin == 1 << 10);
2447 static_assert(ProfileCompilationInfo::MethodHotness::kFlagStartupMaxBin == 1 << 15);
2448 static_assert(ProfileCompilationInfo::MethodHotness::kFlagLastBoot == 1 << 15);
2449 
GetUsedBitmapFlags() const2450 uint16_t ProfileCompilationInfo::DexFileData::GetUsedBitmapFlags() const {
2451   uint32_t used_flags = 0u;
2452   ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2453     size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2454     if (method_bitmap.HasSomeBitSet(index * num_method_ids, num_method_ids)) {
2455       used_flags |= flag;
2456     }
2457     return true;
2458   });
2459   return dchecked_integral_cast<uint16_t>(used_flags);
2460 }
2461 
2462 ProfileCompilationInfo::DexPcData*
FindOrAddDexPc(InlineCacheMap * inline_cache,uint32_t dex_pc)2463 ProfileCompilationInfo::FindOrAddDexPc(InlineCacheMap* inline_cache, uint32_t dex_pc) {
2464   return &(inline_cache->FindOrAdd(dex_pc, DexPcData(inline_cache->get_allocator()))->second);
2465 }
2466 
GetClassDescriptors(const std::vector<const DexFile * > & dex_files,const ProfileSampleAnnotation & annotation)2467 HashSet<std::string> ProfileCompilationInfo::GetClassDescriptors(
2468     const std::vector<const DexFile*>& dex_files,
2469     const ProfileSampleAnnotation& annotation) {
2470   HashSet<std::string> ret;
2471   for (const DexFile* dex_file : dex_files) {
2472     const DexFileData* data = FindDexDataUsingAnnotations(dex_file, annotation);
2473     if (data != nullptr) {
2474       for (dex::TypeIndex type_idx : data->class_set) {
2475         ret.insert(GetTypeDescriptor(dex_file, type_idx));
2476       }
2477     } else {
2478       VLOG(compiler) << "Failed to find profile data for " << dex_file->GetLocation();
2479     }
2480   }
2481   return ret;
2482 }
2483 
IsProfileFile(int fd)2484 bool ProfileCompilationInfo::IsProfileFile(int fd) {
2485   // First check if it's an empty file as we allow empty profile files.
2486   // Profiles may be created by ActivityManager or installd before we manage to
2487   // process them in the runtime or profman.
2488   struct stat stat_buffer;
2489   if (fstat(fd, &stat_buffer) != 0) {
2490     return false;
2491   }
2492 
2493   if (stat_buffer.st_size == 0) {
2494     return true;
2495   }
2496 
2497   // The files is not empty. Check if it contains the profile magic.
2498   size_t byte_count = sizeof(kProfileMagic);
2499   uint8_t buffer[sizeof(kProfileMagic)];
2500   if (!android::base::ReadFullyAtOffset(fd, buffer, byte_count, /*offset=*/ 0)) {
2501     return false;
2502   }
2503 
2504   // Reset the offset to prepare the file for reading.
2505   off_t rc =  TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET));
2506   if (rc == static_cast<off_t>(-1)) {
2507     PLOG(ERROR) << "Failed to reset the offset";
2508     return false;
2509   }
2510 
2511   return memcmp(buffer, kProfileMagic, byte_count) == 0;
2512 }
2513 
UpdateProfileKeys(const std::vector<std::unique_ptr<const DexFile>> & dex_files,bool * matched)2514 bool ProfileCompilationInfo::UpdateProfileKeys(
2515     const std::vector<std::unique_ptr<const DexFile>>& dex_files, /*out*/ bool* matched) {
2516   // This check aligns with when dex2oat falls back from "speed-profile" to "verify".
2517   //
2518   // ART Service relies on the exit code of profman, which is determined by the value of `matched`,
2519   // to judge whether it should re-dexopt for "speed-profile". Therefore, a misalignment will cause
2520   // repeated dexopt.
2521   if (IsEmpty()) {
2522     *matched = false;
2523     return true;
2524   }
2525   DCHECK(!info_.empty());
2526 
2527   *matched = true;
2528 
2529   // A map from the old base key to the new base key.
2530   std::unordered_map<std::string, std::string> old_key_to_new_key;
2531 
2532   // A map from the new base key to all matching old base keys (an invert of the map above), for
2533   // detecting duplicate keys.
2534   std::unordered_map<std::string, std::unordered_set<std::string>> new_key_to_old_keys;
2535 
2536   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2537     std::string old_base_key = GetBaseKeyFromAugmentedKey(dex_data->profile_key);
2538     bool found = false;
2539     for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
2540       if (dex_data->checksum == dex_file->GetLocationChecksum() &&
2541           dex_data->num_type_ids == dex_file->NumTypeIds() &&
2542           dex_data->num_method_ids == dex_file->NumMethodIds()) {
2543         std::string new_base_key = GetProfileDexFileBaseKey(dex_file->GetLocation());
2544         old_key_to_new_key[old_base_key] = new_base_key;
2545         new_key_to_old_keys[new_base_key].insert(old_base_key);
2546         found = true;
2547         break;
2548       }
2549     }
2550     if (!found) {
2551       *matched = false;
2552       // Keep the old key.
2553       old_key_to_new_key[old_base_key] = old_base_key;
2554       new_key_to_old_keys[old_base_key].insert(old_base_key);
2555     }
2556   }
2557 
2558   for (const auto& [new_key, old_keys] : new_key_to_old_keys) {
2559     if (old_keys.size() > 1) {
2560       LOG(ERROR) << "Cannot update multiple profile keys [" << android::base::Join(old_keys, ", ")
2561                  << "] to the same new key '" << new_key << "'";
2562       return false;
2563     }
2564   }
2565 
2566   // Check passed. Now perform the actual mutation.
2567   profile_key_map_.clear();
2568 
2569   for (const std::unique_ptr<DexFileData>& dex_data : info_) {
2570     std::string old_base_key = GetBaseKeyFromAugmentedKey(dex_data->profile_key);
2571     const std::string& new_base_key = old_key_to_new_key[old_base_key];
2572     DCHECK(!new_base_key.empty());
2573     // Retain the annotation (if any) during the renaming by re-attaching the info from the old key.
2574     dex_data->profile_key = MigrateAnnotationInfo(new_base_key, dex_data->profile_key);
2575     profile_key_map_.Put(dex_data->profile_key, dex_data->profile_index);
2576   }
2577 
2578   return true;
2579 }
2580 
ProfileFilterFnAcceptAll(const std::string & dex_location,uint32_t checksum)2581 bool ProfileCompilationInfo::ProfileFilterFnAcceptAll(
2582     [[maybe_unused]] const std::string& dex_location, [[maybe_unused]] uint32_t checksum) {
2583   return true;
2584 }
2585 
ClearData()2586 void ProfileCompilationInfo::ClearData() {
2587   profile_key_map_.clear();
2588   info_.clear();
2589   extra_descriptors_indexes_.clear();
2590   extra_descriptors_.clear();
2591 }
2592 
ClearDataAndAdjustVersion(bool for_boot_image)2593 void ProfileCompilationInfo::ClearDataAndAdjustVersion(bool for_boot_image) {
2594   ClearData();
2595   memcpy(version_,
2596          for_boot_image ? kProfileVersionForBootImage : kProfileVersion,
2597          kProfileVersionSize);
2598 }
2599 
IsForBootImage() const2600 bool ProfileCompilationInfo::IsForBootImage() const {
2601   return memcmp(version_, kProfileVersionForBootImage, sizeof(kProfileVersionForBootImage)) == 0;
2602 }
2603 
GetVersion() const2604 const uint8_t* ProfileCompilationInfo::GetVersion() const {
2605   return version_;
2606 }
2607 
ContainsClass(dex::TypeIndex type_index) const2608 bool ProfileCompilationInfo::DexFileData::ContainsClass(dex::TypeIndex type_index) const {
2609   return class_set.find(type_index) != class_set.end();
2610 }
2611 
ClassesDataSize() const2612 uint32_t ProfileCompilationInfo::DexFileData::ClassesDataSize() const {
2613   return class_set.empty()
2614       ? 0u
2615       : sizeof(ProfileIndexType) +            // Which dex file.
2616         sizeof(uint16_t) +                    // Number of classes.
2617         sizeof(uint16_t) * class_set.size();  // Type index diffs.
2618 }
2619 
WriteClasses(SafeBuffer & buffer) const2620 void ProfileCompilationInfo::DexFileData::WriteClasses(SafeBuffer& buffer) const {
2621   if (class_set.empty()) {
2622     return;
2623   }
2624   buffer.WriteUintAndAdvance(profile_index);
2625   buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(class_set.size()));
2626   WriteClassSet(buffer, class_set);
2627 }
2628 
ReadClasses(SafeBuffer & buffer,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)2629 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::ReadClasses(
2630     SafeBuffer& buffer,
2631     const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
2632     std::string* error) {
2633   uint16_t classes_size;
2634   if (!buffer.ReadUintAndAdvance(&classes_size)) {
2635     *error = "Error reading classes size.";
2636     return ProfileLoadStatus::kBadData;
2637   }
2638   uint16_t num_valid_type_indexes = dchecked_integral_cast<uint16_t>(
2639       std::min<size_t>(num_type_ids + extra_descriptors_remap.size(), DexFile::kDexNoIndex16));
2640   uint16_t type_index = 0u;
2641   for (size_t i = 0; i != classes_size; ++i) {
2642     uint16_t type_index_diff;
2643     if (!buffer.ReadUintAndAdvance(&type_index_diff)) {
2644       *error = "Error reading class type index diff.";
2645       return ProfileLoadStatus::kBadData;
2646     }
2647     if (type_index_diff == 0u && i != 0u) {
2648       *error = "Duplicate type index.";
2649       return ProfileLoadStatus::kBadData;
2650     }
2651     if (type_index_diff >= num_valid_type_indexes - type_index) {
2652       *error = "Invalid type index.";
2653       return ProfileLoadStatus::kBadData;
2654     }
2655     type_index += type_index_diff;
2656     if (type_index >= num_type_ids) {
2657       uint32_t new_extra_descriptor_index = extra_descriptors_remap[type_index - num_type_ids];
2658       if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2659         *error = "Remapped type index out of range.";
2660         return ProfileLoadStatus::kMergeError;
2661       }
2662       class_set.insert(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
2663     } else {
2664       class_set.insert(dex::TypeIndex(type_index));
2665     }
2666   }
2667   return ProfileLoadStatus::kSuccess;
2668 }
2669 
SkipClasses(SafeBuffer & buffer,std::string * error)2670 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::SkipClasses(
2671     SafeBuffer& buffer,
2672     std::string* error) {
2673   uint16_t classes_size;
2674   if (!buffer.ReadUintAndAdvance(&classes_size)) {
2675     *error = "Error reading classes size to skip.";
2676     return ProfileLoadStatus::kBadData;
2677   }
2678   size_t following_data_size = static_cast<size_t>(classes_size) * sizeof(uint16_t);
2679   if (following_data_size > buffer.GetAvailableBytes()) {
2680     *error = "Classes data size to skip exceeds remaining data.";
2681     return ProfileLoadStatus::kBadData;
2682   }
2683   buffer.Advance(following_data_size);
2684   return ProfileLoadStatus::kSuccess;
2685 }
2686 
MethodsDataSize(uint16_t * method_flags,size_t * saved_bitmap_bit_size) const2687 uint32_t ProfileCompilationInfo::DexFileData::MethodsDataSize(
2688     /*out*/ uint16_t* method_flags,
2689     /*out*/ size_t* saved_bitmap_bit_size) const {
2690   uint16_t local_method_flags = GetUsedBitmapFlags();
2691   size_t local_saved_bitmap_bit_size = POPCOUNT(local_method_flags) * num_method_ids;
2692   if (!method_map.empty()) {
2693     local_method_flags |= enum_cast<uint16_t>(MethodHotness::kFlagHot);
2694   }
2695   size_t size = 0u;
2696   if (local_method_flags != 0u) {
2697     size_t num_hot_methods = method_map.size();
2698     size_t num_dex_pc_entries = 0u;
2699     size_t num_class_entries = 0u;
2700     for (const auto& method_entry : method_map) {
2701       const InlineCacheMap& inline_cache_map = method_entry.second;
2702       num_dex_pc_entries += inline_cache_map.size();
2703       for (const auto& inline_cache_entry : inline_cache_map) {
2704         const DexPcData& dex_pc_data = inline_cache_entry.second;
2705         num_class_entries += dex_pc_data.classes.size();
2706       }
2707     }
2708 
2709     constexpr size_t kPerHotMethodSize =
2710         sizeof(uint16_t) +  // Method index diff.
2711         sizeof(uint16_t);   // Inline cache size.
2712     constexpr size_t kPerDexPcEntrySize =
2713         sizeof(uint16_t) +  // Dex PC.
2714         sizeof(uint8_t);    // Number of inline cache classes.
2715     constexpr size_t kPerClassEntrySize =
2716         sizeof(uint16_t);   // Type index diff.
2717 
2718     size_t saved_bitmap_byte_size = BitsToBytesRoundUp(local_saved_bitmap_bit_size);
2719     size = sizeof(ProfileIndexType) +                 // Which dex file.
2720            sizeof(uint32_t) +                         // Total size of following data.
2721            sizeof(uint16_t) +                         // Method flags.
2722            saved_bitmap_byte_size +                   // Bitmap data.
2723            num_hot_methods * kPerHotMethodSize +      // Data for hot methods.
2724            num_dex_pc_entries * kPerDexPcEntrySize +  // Data for dex pc entries.
2725            num_class_entries * kPerClassEntrySize;    // Data for inline cache class entries.
2726   }
2727   if (method_flags != nullptr) {
2728     *method_flags = local_method_flags;
2729   }
2730   if (saved_bitmap_bit_size != nullptr) {
2731     *saved_bitmap_bit_size = local_saved_bitmap_bit_size;
2732   }
2733   return size;
2734 }
2735 
WriteMethods(SafeBuffer & buffer) const2736 void ProfileCompilationInfo::DexFileData::WriteMethods(SafeBuffer& buffer) const {
2737   uint16_t method_flags;
2738   size_t saved_bitmap_bit_size;
2739   uint32_t methods_data_size = MethodsDataSize(&method_flags, &saved_bitmap_bit_size);
2740   if (methods_data_size == 0u) {
2741     return;  // No data to write.
2742   }
2743   DCHECK_GE(buffer.GetAvailableBytes(), methods_data_size);
2744   uint32_t expected_available_bytes_at_end = buffer.GetAvailableBytes() - methods_data_size;
2745 
2746   // Write the profile index.
2747   buffer.WriteUintAndAdvance(profile_index);
2748   // Write the total size of the following methods data (without the profile index
2749   // and the total size itself) for easy skipping when the dex file is filtered out.
2750   uint32_t following_data_size = methods_data_size - sizeof(ProfileIndexType) - sizeof(uint32_t);
2751   buffer.WriteUintAndAdvance(following_data_size);
2752   // Write the used method flags.
2753   buffer.WriteUintAndAdvance(method_flags);
2754 
2755   // Write the bitmap data.
2756   size_t saved_bitmap_byte_size = BitsToBytesRoundUp(saved_bitmap_bit_size);
2757   DCHECK_LE(saved_bitmap_byte_size, buffer.GetAvailableBytes());
2758   BitMemoryRegion saved_bitmap(buffer.GetCurrentPtr(), /*bit_start=*/ 0, saved_bitmap_bit_size);
2759   size_t saved_bitmap_index = 0u;
2760   ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2761     if ((method_flags & flag) != 0u) {
2762       size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2763       BitMemoryRegion src = method_bitmap.Subregion(index * num_method_ids, num_method_ids);
2764       saved_bitmap.Subregion(saved_bitmap_index * num_method_ids, num_method_ids).CopyBits(src);
2765       ++saved_bitmap_index;
2766     }
2767     return true;
2768   });
2769   DCHECK_EQ(saved_bitmap_index * num_method_ids, saved_bitmap_bit_size);
2770   // Clear the padding bits.
2771   size_t padding_bit_size = saved_bitmap_byte_size * kBitsPerByte - saved_bitmap_bit_size;
2772   BitMemoryRegion padding_region(buffer.GetCurrentPtr(), saved_bitmap_bit_size, padding_bit_size);
2773   padding_region.StoreBits(/*bit_offset=*/ 0u, /*value=*/ 0u, /*bit_length=*/ padding_bit_size);
2774   buffer.Advance(saved_bitmap_byte_size);
2775 
2776   uint16_t last_method_index = 0;
2777   for (const auto& method_entry : method_map) {
2778     uint16_t method_index = method_entry.first;
2779     const InlineCacheMap& inline_cache_map = method_entry.second;
2780 
2781     // Store the difference between the method indices for better compression.
2782     // The SafeMap is ordered by method_id, so the difference will always be non negative.
2783     DCHECK_GE(method_index, last_method_index);
2784     uint16_t diff_with_last_method_index = method_index - last_method_index;
2785     last_method_index = method_index;
2786     buffer.WriteUintAndAdvance(diff_with_last_method_index);
2787 
2788     // Add inline cache map size.
2789     buffer.WriteUintAndAdvance(dchecked_integral_cast<uint16_t>(inline_cache_map.size()));
2790 
2791     // Add inline cache entries.
2792     for (const auto& inline_cache_entry : inline_cache_map) {
2793       uint16_t dex_pc = inline_cache_entry.first;
2794       const DexPcData& dex_pc_data = inline_cache_entry.second;
2795       const ArenaSet<dex::TypeIndex>& classes = dex_pc_data.classes;
2796 
2797       // Add the dex pc.
2798       buffer.WriteUintAndAdvance(dex_pc);
2799 
2800       // Add the megamorphic/missing_types encoding if needed and continue.
2801       // In either cases we don't add any classes to the profiles and so there's
2802       // no point to continue.
2803       // TODO: in case we miss types there is still value to add the rest of the
2804       // classes. (This requires changing profile version or using a new section type.)
2805       if (dex_pc_data.is_missing_types) {
2806         // At this point the megamorphic flag should not be set.
2807         DCHECK(!dex_pc_data.is_megamorphic);
2808         DCHECK_EQ(classes.size(), 0u);
2809         buffer.WriteUintAndAdvance(kIsMissingTypesEncoding);
2810         continue;
2811       } else if (dex_pc_data.is_megamorphic) {
2812         DCHECK_EQ(classes.size(), 0u);
2813         buffer.WriteUintAndAdvance(kIsMegamorphicEncoding);
2814         continue;
2815       }
2816 
2817       DCHECK_LT(classes.size(), ProfileCompilationInfo::kIndividualInlineCacheSize);
2818       DCHECK_NE(classes.size(), 0u) << "InlineCache contains a dex_pc with 0 classes";
2819 
2820       // Add the number of classes for the dex PC.
2821       buffer.WriteUintAndAdvance(dchecked_integral_cast<uint8_t>(classes.size()));
2822       // Store the class set.
2823       WriteClassSet(buffer, classes);
2824     }
2825   }
2826 
2827   // Check if we've written the right number of bytes.
2828   DCHECK_EQ(buffer.GetAvailableBytes(), expected_available_bytes_at_end);
2829 }
2830 
ReadMethods(SafeBuffer & buffer,const dchecked_vector<ExtraDescriptorIndex> & extra_descriptors_remap,std::string * error)2831 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::ReadMethods(
2832     SafeBuffer& buffer,
2833     const dchecked_vector<ExtraDescriptorIndex>& extra_descriptors_remap,
2834     std::string* error) {
2835   uint32_t following_data_size;
2836   if (!buffer.ReadUintAndAdvance(&following_data_size)) {
2837     *error = "Error reading methods data size.";
2838     return ProfileLoadStatus::kBadData;
2839   }
2840   if (following_data_size > buffer.GetAvailableBytes()) {
2841     *error = "Methods data size exceeds available data size.";
2842     return ProfileLoadStatus::kBadData;
2843   }
2844   uint32_t expected_available_bytes_at_end = buffer.GetAvailableBytes() - following_data_size;
2845 
2846   // Read method flags.
2847   uint16_t method_flags;
2848   if (!buffer.ReadUintAndAdvance(&method_flags)) {
2849     *error = "Error reading method flags.";
2850     return ProfileLoadStatus::kBadData;
2851   }
2852   if (!is_for_boot_image && method_flags >= (MethodHotness::kFlagLastRegular << 1)) {
2853     // The profile we're loading contains data for boot image.
2854     *error = "Method flags contain boot image profile flags for non-boot image profile.";
2855     return ProfileLoadStatus::kBadData;
2856   }
2857 
2858   // Read method bitmap.
2859   size_t saved_bitmap_bit_size = POPCOUNT(method_flags & ~MethodHotness::kFlagHot) * num_method_ids;
2860   size_t saved_bitmap_byte_size = BitsToBytesRoundUp(saved_bitmap_bit_size);
2861   if (sizeof(uint16_t) + saved_bitmap_byte_size > following_data_size) {
2862     *error = "Insufficient available data for method bitmap.";
2863     return ProfileLoadStatus::kBadData;
2864   }
2865   BitMemoryRegion saved_bitmap(buffer.GetCurrentPtr(), /*bit_start=*/ 0, saved_bitmap_bit_size);
2866   size_t saved_bitmap_index = 0u;
2867   ForMethodBitmapHotnessFlags([&](MethodHotness::Flag flag) {
2868     if ((method_flags & flag) != 0u) {
2869       size_t index = FlagBitmapIndex(static_cast<MethodHotness::Flag>(flag));
2870       BitMemoryRegion src =
2871           saved_bitmap.Subregion(saved_bitmap_index * num_method_ids, num_method_ids);
2872       method_bitmap.Subregion(index * num_method_ids, num_method_ids).OrBits(src);
2873       ++saved_bitmap_index;
2874     }
2875     return true;
2876   });
2877   buffer.Advance(saved_bitmap_byte_size);
2878 
2879   // Load hot methods.
2880   if ((method_flags & MethodHotness::kFlagHot) != 0u) {
2881     uint32_t num_valid_method_indexes =
2882         std::min<uint32_t>(kMaxSupportedMethodIndex + 1u, num_method_ids);
2883     uint16_t num_valid_type_indexes = dchecked_integral_cast<uint16_t>(
2884         std::min<size_t>(num_type_ids + extra_descriptors_remap.size(), DexFile::kDexNoIndex16));
2885     uint16_t method_index = 0;
2886     bool first_diff = true;
2887     while (buffer.GetAvailableBytes() > expected_available_bytes_at_end) {
2888       uint16_t diff_with_last_method_index;
2889       if (!buffer.ReadUintAndAdvance(&diff_with_last_method_index)) {
2890         *error = "Error reading method index diff.";
2891         return ProfileLoadStatus::kBadData;
2892       }
2893       if (diff_with_last_method_index == 0u && !first_diff) {
2894         *error = "Duplicate method index.";
2895         return ProfileLoadStatus::kBadData;
2896       }
2897       first_diff = false;
2898       if (diff_with_last_method_index >= num_valid_method_indexes - method_index) {
2899         *error = "Invalid method index.";
2900         return ProfileLoadStatus::kBadData;
2901       }
2902       method_index += diff_with_last_method_index;
2903       InlineCacheMap* inline_cache = FindOrAddHotMethod(method_index);
2904       DCHECK(inline_cache != nullptr);
2905 
2906       // Load inline cache map size.
2907       uint16_t inline_cache_size;
2908       if (!buffer.ReadUintAndAdvance(&inline_cache_size)) {
2909         *error = "Error reading inline cache size.";
2910         return ProfileLoadStatus::kBadData;
2911       }
2912       for (uint16_t ic_index = 0; ic_index != inline_cache_size; ++ic_index) {
2913         // Load dex pc.
2914         uint16_t dex_pc;
2915         if (!buffer.ReadUintAndAdvance(&dex_pc)) {
2916           *error = "Error reading inline cache dex pc.";
2917           return ProfileLoadStatus::kBadData;
2918         }
2919         DexPcData* dex_pc_data = FindOrAddDexPc(inline_cache, dex_pc);
2920         DCHECK(dex_pc_data != nullptr);
2921 
2922         // Load inline cache classes.
2923         uint8_t inline_cache_classes_size;
2924         if (!buffer.ReadUintAndAdvance(&inline_cache_classes_size)) {
2925           *error = "Error reading inline cache classes size.";
2926           return ProfileLoadStatus::kBadData;
2927         }
2928         if (inline_cache_classes_size == kIsMissingTypesEncoding) {
2929           dex_pc_data->SetIsMissingTypes();
2930         } else if (inline_cache_classes_size == kIsMegamorphicEncoding) {
2931           dex_pc_data->SetIsMegamorphic();
2932         } else if (inline_cache_classes_size >= kIndividualInlineCacheSize) {
2933           *error = "Inline cache size too large.";
2934           return ProfileLoadStatus::kBadData;
2935         } else {
2936           uint16_t type_index = 0u;
2937           for (size_t i = 0; i != inline_cache_classes_size; ++i) {
2938             uint16_t type_index_diff;
2939             if (!buffer.ReadUintAndAdvance(&type_index_diff)) {
2940               *error = "Error reading inline cache type index diff.";
2941               return ProfileLoadStatus::kBadData;
2942             }
2943             if (type_index_diff == 0u && i != 0u) {
2944               *error = "Duplicate inline cache type index.";
2945               return ProfileLoadStatus::kBadData;
2946             }
2947             if (type_index_diff >= num_valid_type_indexes - type_index) {
2948               *error = "Invalid inline cache type index.";
2949               return ProfileLoadStatus::kBadData;
2950             }
2951             type_index += type_index_diff;
2952             if (type_index >= num_type_ids) {
2953               ExtraDescriptorIndex new_extra_descriptor_index =
2954                   extra_descriptors_remap[type_index - num_type_ids];
2955               if (new_extra_descriptor_index >= DexFile::kDexNoIndex16 - num_type_ids) {
2956                 *error = "Remapped inline cache type index out of range.";
2957                 return ProfileLoadStatus::kMergeError;
2958               }
2959               dex_pc_data->AddClass(dex::TypeIndex(num_type_ids + new_extra_descriptor_index));
2960             } else {
2961               dex_pc_data->AddClass(dex::TypeIndex(type_index));
2962             }
2963           }
2964         }
2965       }
2966     }
2967   }
2968 
2969   if (buffer.GetAvailableBytes() != expected_available_bytes_at_end) {
2970     *error = "Methods data did not end at expected position.";
2971     return ProfileLoadStatus::kBadData;
2972   }
2973 
2974   return ProfileLoadStatus::kSuccess;
2975 }
2976 
SkipMethods(SafeBuffer & buffer,std::string * error)2977 ProfileCompilationInfo::ProfileLoadStatus ProfileCompilationInfo::DexFileData::SkipMethods(
2978     SafeBuffer& buffer,
2979     std::string* error) {
2980   uint32_t following_data_size;
2981   if (!buffer.ReadUintAndAdvance(&following_data_size)) {
2982     *error = "Error reading methods data size to skip.";
2983     return ProfileLoadStatus::kBadData;
2984   }
2985   if (following_data_size > buffer.GetAvailableBytes()) {
2986     *error = "Methods data size to skip exceeds remaining data.";
2987     return ProfileLoadStatus::kBadData;
2988   }
2989   buffer.Advance(following_data_size);
2990   return ProfileLoadStatus::kSuccess;
2991 }
2992 
WriteClassSet(SafeBuffer & buffer,const ArenaSet<dex::TypeIndex> & class_set)2993 void ProfileCompilationInfo::DexFileData::WriteClassSet(
2994     SafeBuffer& buffer,
2995     const ArenaSet<dex::TypeIndex>& class_set) {
2996   // Store the difference between the type indexes for better compression.
2997   uint16_t last_type_index = 0u;
2998   for (const dex::TypeIndex& type_index : class_set) {
2999     DCHECK_GE(type_index.index_, last_type_index);
3000     uint16_t diff_with_last_type_index = type_index.index_ - last_type_index;
3001     last_type_index = type_index.index_;
3002     buffer.WriteUintAndAdvance(diff_with_last_type_index);
3003   }
3004 }
3005 
GetSizeWarningThresholdBytes() const3006 size_t ProfileCompilationInfo::GetSizeWarningThresholdBytes() const {
3007   return IsForBootImage() ?  kSizeWarningThresholdBootBytes : kSizeWarningThresholdBytes;
3008 }
3009 
GetSizeErrorThresholdBytes() const3010 size_t ProfileCompilationInfo::GetSizeErrorThresholdBytes() const {
3011   return IsForBootImage() ?  kSizeErrorThresholdBootBytes : kSizeErrorThresholdBytes;
3012 }
3013 
operator <<(std::ostream & stream,ProfileCompilationInfo::DexReferenceDumper dumper)3014 std::ostream& operator<<(std::ostream& stream,
3015                          ProfileCompilationInfo::DexReferenceDumper dumper) {
3016   stream << "[profile_key=" << dumper.GetProfileKey()
3017          << ",dex_checksum=" << std::hex << dumper.GetDexChecksum() << std::dec
3018          << ",num_type_ids=" << dumper.GetNumTypeIds()
3019          << ",num_method_ids=" << dumper.GetNumMethodIds()
3020          << "]";
3021   return stream;
3022 }
3023 
FlattenProfileData()3024 FlattenProfileData::FlattenProfileData() :
3025     max_aggregation_for_methods_(0),
3026     max_aggregation_for_classes_(0) {
3027 }
3028 
ItemMetadata()3029 FlattenProfileData::ItemMetadata::ItemMetadata() :
3030     flags_(0) {
3031 }
3032 
ItemMetadata(const ItemMetadata & other)3033 FlattenProfileData::ItemMetadata::ItemMetadata(const ItemMetadata& other) :
3034     flags_(other.flags_),
3035     annotations_(other.annotations_) {
3036 }
3037 
ExtractProfileData(const std::vector<std::unique_ptr<const DexFile>> & dex_files) const3038 std::unique_ptr<FlattenProfileData> ProfileCompilationInfo::ExtractProfileData(
3039     const std::vector<std::unique_ptr<const DexFile>>& dex_files) const {
3040 
3041   std::unique_ptr<FlattenProfileData> result(new FlattenProfileData());
3042 
3043   auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
3044 
3045   // Iterate through all the dex files, find the methods/classes associated with each of them,
3046   // and add them to the flatten result.
3047   for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
3048     // Find all the dex data for the given dex file.
3049     // We may have multiple dex data if the methods or classes were added using
3050     // different annotations.
3051     std::vector<const DexFileData*> all_dex_data;
3052     FindAllDexData(dex_file.get(), &all_dex_data);
3053     for (const DexFileData* dex_data : all_dex_data) {
3054       // Extract the annotation from the key as we want to store it in the flatten result.
3055       ProfileSampleAnnotation annotation = GetAnnotationFromKey(dex_data->profile_key);
3056 
3057       // Check which methods from the current dex files are in the profile.
3058       for (uint32_t method_idx = 0; method_idx < dex_data->num_method_ids; ++method_idx) {
3059         MethodHotness hotness = dex_data->GetHotnessInfo(method_idx);
3060         if (!hotness.IsInProfile()) {
3061           // Not in the profile, continue.
3062           continue;
3063         }
3064         // The method is in the profile, create metadata item for it and added to the result.
3065         MethodReference ref(dex_file.get(), method_idx);
3066         FlattenProfileData::ItemMetadata& metadata =
3067             result->method_metadata_.GetOrCreate(ref, create_metadata_fn);
3068         metadata.flags_ |= hotness.flags_;
3069         metadata.annotations_.push_back(annotation);
3070         // Update the max aggregation counter for methods.
3071         // This is essentially a cache, to avoid traversing all the methods just to find out
3072         // this value.
3073         result->max_aggregation_for_methods_ = std::max(
3074             result->max_aggregation_for_methods_,
3075             static_cast<uint32_t>(metadata.annotations_.size()));
3076       }
3077 
3078       // Check which classes from the current dex files are in the profile.
3079       for (const dex::TypeIndex& type_index : dex_data->class_set) {
3080         if (type_index.index_ >= dex_file->NumTypeIds()) {
3081           // Not a valid `dex::TypeIndex` for `TypeReference`.
3082           // TODO: Rewrite the API to use descriptors or the `ProfileCompilationInfo` directly
3083           // instead of the `FlattenProfileData` helper class.
3084           continue;
3085         }
3086         TypeReference ref(dex_file.get(), type_index);
3087         FlattenProfileData::ItemMetadata& metadata =
3088             result->class_metadata_.GetOrCreate(ref, create_metadata_fn);
3089         metadata.annotations_.push_back(annotation);
3090         // Update the max aggregation counter for classes.
3091         result->max_aggregation_for_classes_ = std::max(
3092             result->max_aggregation_for_classes_,
3093             static_cast<uint32_t>(metadata.annotations_.size()));
3094       }
3095     }
3096   }
3097 
3098   return result;
3099 }
3100 
MergeData(const FlattenProfileData & other)3101 void FlattenProfileData::MergeData(const FlattenProfileData& other) {
3102   auto create_metadata_fn = []() { return FlattenProfileData::ItemMetadata(); };
3103   for (const auto& it : other.method_metadata_) {
3104     const MethodReference& otherRef = it.first;
3105     const FlattenProfileData::ItemMetadata otherData = it.second;
3106     const std::list<ProfileCompilationInfo::ProfileSampleAnnotation>& other_annotations =
3107         otherData.GetAnnotations();
3108 
3109     FlattenProfileData::ItemMetadata& metadata =
3110         method_metadata_.GetOrCreate(otherRef, create_metadata_fn);
3111     metadata.flags_ |= otherData.GetFlags();
3112     metadata.annotations_.insert(
3113         metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
3114 
3115     max_aggregation_for_methods_ = std::max(
3116           max_aggregation_for_methods_,
3117           static_cast<uint32_t>(metadata.annotations_.size()));
3118   }
3119   for (const auto& it : other.class_metadata_) {
3120     const TypeReference& otherRef = it.first;
3121     const FlattenProfileData::ItemMetadata otherData = it.second;
3122     const std::list<ProfileCompilationInfo::ProfileSampleAnnotation>& other_annotations =
3123         otherData.GetAnnotations();
3124 
3125     FlattenProfileData::ItemMetadata& metadata =
3126         class_metadata_.GetOrCreate(otherRef, create_metadata_fn);
3127     metadata.flags_ |= otherData.GetFlags();
3128     metadata.annotations_.insert(
3129         metadata.annotations_.end(), other_annotations.begin(), other_annotations.end());
3130 
3131     max_aggregation_for_classes_ = std::max(
3132           max_aggregation_for_classes_,
3133           static_cast<uint32_t>(metadata.annotations_.size()));
3134   }
3135 }
3136 
3137 }  // namespace art
3138