Home | History | Annotate | Download | only in hiddenapi
      1 /*
      2  * Copyright (C) 2017 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 <fstream>
     18 #include <iostream>
     19 #include <map>
     20 #include <set>
     21 #include <string>
     22 #include <string_view>
     23 
     24 #include "android-base/stringprintf.h"
     25 #include "android-base/strings.h"
     26 
     27 #include "base/bit_utils.h"
     28 #include "base/hiddenapi_flags.h"
     29 #include "base/mem_map.h"
     30 #include "base/os.h"
     31 #include "base/stl_util.h"
     32 #include "base/string_view_cpp20.h"
     33 #include "base/unix_file/fd_file.h"
     34 #include "dex/art_dex_file_loader.h"
     35 #include "dex/class_accessor-inl.h"
     36 #include "dex/dex_file-inl.h"
     37 
     38 namespace art {
     39 namespace hiddenapi {
     40 
     41 const char kErrorHelp[] = "\nSee go/hiddenapi-error for help.";
     42 
     43 static int original_argc;
     44 static char** original_argv;
     45 
     46 static std::string CommandLine() {
     47   std::vector<std::string> command;
     48   command.reserve(original_argc);
     49   for (int i = 0; i < original_argc; ++i) {
     50     command.push_back(original_argv[i]);
     51   }
     52   return android::base::Join(command, ' ');
     53 }
     54 
     55 static void UsageErrorV(const char* fmt, va_list ap) {
     56   std::string error;
     57   android::base::StringAppendV(&error, fmt, ap);
     58   LOG(ERROR) << error;
     59 }
     60 
     61 static void UsageError(const char* fmt, ...) {
     62   va_list ap;
     63   va_start(ap, fmt);
     64   UsageErrorV(fmt, ap);
     65   va_end(ap);
     66 }
     67 
     68 NO_RETURN static void Usage(const char* fmt, ...) {
     69   va_list ap;
     70   va_start(ap, fmt);
     71   UsageErrorV(fmt, ap);
     72   va_end(ap);
     73 
     74   UsageError("Command: %s", CommandLine().c_str());
     75   UsageError("Usage: hiddenapi [command_name] [options]...");
     76   UsageError("");
     77   UsageError("  Command \"encode\": encode API list membership in boot dex files");
     78   UsageError("    --input-dex=<filename>: dex file which belongs to boot class path");
     79   UsageError("    --output-dex=<filename>: file to write encoded dex into");
     80   UsageError("        input and output dex files are paired in order of appearance");
     81   UsageError("");
     82   UsageError("    --api-flags=<filename>:");
     83   UsageError("        CSV file with signatures of methods/fields and their respective flags");
     84   UsageError("");
     85   UsageError("    --no-force-assign-all:");
     86   UsageError("        Disable check that all dex entries have been assigned a flag");
     87   UsageError("");
     88   UsageError("  Command \"list\": dump lists of public and private API");
     89   UsageError("    --boot-dex=<filename>: dex file which belongs to boot class path");
     90   UsageError("    --public-stub-classpath=<filenames>:");
     91   UsageError("    --system-stub-classpath=<filenames>:");
     92   UsageError("    --test-stub-classpath=<filenames>:");
     93   UsageError("    --core-platform-stub-classpath=<filenames>:");
     94   UsageError("        colon-separated list of dex/apk files which form API stubs of boot");
     95   UsageError("        classpath. Multiple classpaths can be specified");
     96   UsageError("");
     97   UsageError("    --out-api-flags=<filename>: output file for a CSV file with API flags");
     98   UsageError("");
     99 
    100   exit(EXIT_FAILURE);
    101 }
    102 
    103 template<typename E>
    104 static bool Contains(const std::vector<E>& vec, const E& elem) {
    105   return std::find(vec.begin(), vec.end(), elem) != vec.end();
    106 }
    107 
    108 class DexClass : public ClassAccessor {
    109  public:
    110   explicit DexClass(const ClassAccessor& accessor) : ClassAccessor(accessor) {}
    111 
    112   const uint8_t* GetData() const { return dex_file_.GetClassData(GetClassDef()); }
    113 
    114   const dex::TypeIndex GetSuperclassIndex() const { return GetClassDef().superclass_idx_; }
    115 
    116   bool HasSuperclass() const { return dex_file_.IsTypeIndexValid(GetSuperclassIndex()); }
    117 
    118   std::string_view GetSuperclassDescriptor() const {
    119     return HasSuperclass() ? dex_file_.StringByTypeIdx(GetSuperclassIndex()) : "";
    120   }
    121 
    122   std::set<std::string_view> GetInterfaceDescriptors() const {
    123     std::set<std::string_view> list;
    124     const dex::TypeList* ifaces = dex_file_.GetInterfacesList(GetClassDef());
    125     for (uint32_t i = 0; ifaces != nullptr && i < ifaces->Size(); ++i) {
    126       list.insert(dex_file_.StringByTypeIdx(ifaces->GetTypeItem(i).type_idx_));
    127     }
    128     return list;
    129   }
    130 
    131   inline bool IsPublic() const { return HasAccessFlags(kAccPublic); }
    132   inline bool IsInterface() const { return HasAccessFlags(kAccInterface); }
    133 
    134   inline bool Equals(const DexClass& other) const {
    135     bool equals = strcmp(GetDescriptor(), other.GetDescriptor()) == 0;
    136 
    137     if (equals) {
    138       LOG(FATAL) << "Class duplication: " << GetDescriptor() << " in " << dex_file_.GetLocation()
    139           << " and " << other.dex_file_.GetLocation();
    140     }
    141 
    142     return equals;
    143   }
    144 
    145  private:
    146   uint32_t GetAccessFlags() const { return GetClassDef().access_flags_; }
    147   bool HasAccessFlags(uint32_t mask) const { return (GetAccessFlags() & mask) == mask; }
    148 
    149   static std::string JoinStringSet(const std::set<std::string_view>& s) {
    150     return "{" + ::android::base::Join(std::vector<std::string>(s.begin(), s.end()), ",") + "}";
    151   }
    152 };
    153 
    154 class DexMember {
    155  public:
    156   DexMember(const DexClass& klass, const ClassAccessor::Field& item)
    157       : klass_(klass), item_(item), is_method_(false) {
    158     DCHECK_EQ(GetFieldId().class_idx_, klass.GetClassIdx());
    159   }
    160 
    161   DexMember(const DexClass& klass, const ClassAccessor::Method& item)
    162       : klass_(klass), item_(item), is_method_(true) {
    163     DCHECK_EQ(GetMethodId().class_idx_, klass.GetClassIdx());
    164   }
    165 
    166   inline const DexClass& GetDeclaringClass() const { return klass_; }
    167 
    168   inline bool IsMethod() const { return is_method_; }
    169   inline bool IsVirtualMethod() const { return IsMethod() && !GetMethod().IsStaticOrDirect(); }
    170   inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); }
    171 
    172   inline bool IsPublicOrProtected() const {
    173     return HasAccessFlags(kAccPublic) || HasAccessFlags(kAccProtected);
    174   }
    175 
    176   // Constructs a string with a unique signature of this class member.
    177   std::string GetApiEntry() const {
    178     std::stringstream ss;
    179     ss << klass_.GetDescriptor() << "->" << GetName() << (IsMethod() ? "" : ":")
    180        << GetSignature();
    181     return ss.str();
    182   }
    183 
    184   inline bool operator==(const DexMember& other) const {
    185     // These need to match if they should resolve to one another.
    186     bool equals = IsMethod() == other.IsMethod() &&
    187                   GetName() == other.GetName() &&
    188                   GetSignature() == other.GetSignature();
    189 
    190     // Sanity checks if they do match.
    191     if (equals) {
    192       CHECK_EQ(IsVirtualMethod(), other.IsVirtualMethod());
    193     }
    194 
    195     return equals;
    196   }
    197 
    198  private:
    199   inline uint32_t GetAccessFlags() const { return item_.GetAccessFlags(); }
    200   inline uint32_t HasAccessFlags(uint32_t mask) const { return (GetAccessFlags() & mask) == mask; }
    201 
    202   inline std::string_view GetName() const {
    203     return IsMethod() ? item_.GetDexFile().GetMethodName(GetMethodId())
    204                       : item_.GetDexFile().GetFieldName(GetFieldId());
    205   }
    206 
    207   inline std::string GetSignature() const {
    208     return IsMethod() ? item_.GetDexFile().GetMethodSignature(GetMethodId()).ToString()
    209                       : item_.GetDexFile().GetFieldTypeDescriptor(GetFieldId());
    210   }
    211 
    212   inline const ClassAccessor::Method& GetMethod() const {
    213     DCHECK(IsMethod());
    214     return down_cast<const ClassAccessor::Method&>(item_);
    215   }
    216 
    217   inline const dex::MethodId& GetMethodId() const {
    218     DCHECK(IsMethod());
    219     return item_.GetDexFile().GetMethodId(item_.GetIndex());
    220   }
    221 
    222   inline const dex::FieldId& GetFieldId() const {
    223     DCHECK(!IsMethod());
    224     return item_.GetDexFile().GetFieldId(item_.GetIndex());
    225   }
    226 
    227   const DexClass& klass_;
    228   const ClassAccessor::BaseItem& item_;
    229   const bool is_method_;
    230 };
    231 
    232 class ClassPath final {
    233  public:
    234   ClassPath(const std::vector<std::string>& dex_paths, bool open_writable) {
    235     OpenDexFiles(dex_paths, open_writable);
    236   }
    237 
    238   template<typename Fn>
    239   void ForEachDexClass(Fn fn) {
    240     for (auto& dex_file : dex_files_) {
    241       for (ClassAccessor accessor : dex_file->GetClasses()) {
    242         fn(DexClass(accessor));
    243       }
    244     }
    245   }
    246 
    247   template<typename Fn>
    248   void ForEachDexMember(Fn fn) {
    249     ForEachDexClass([&fn](const DexClass& klass) {
    250       for (const ClassAccessor::Field& field : klass.GetFields()) {
    251         fn(DexMember(klass, field));
    252       }
    253       for (const ClassAccessor::Method& method : klass.GetMethods()) {
    254         fn(DexMember(klass, method));
    255       }
    256     });
    257   }
    258 
    259   std::vector<const DexFile*> GetDexFiles() const {
    260     return MakeNonOwningPointerVector(dex_files_);
    261   }
    262 
    263   void UpdateDexChecksums() {
    264     for (auto& dex_file : dex_files_) {
    265       // Obtain a writeable pointer to the dex header.
    266       DexFile::Header* header = const_cast<DexFile::Header*>(&dex_file->GetHeader());
    267       // Recalculate checksum and overwrite the value in the header.
    268       header->checksum_ = dex_file->CalculateChecksum();
    269     }
    270   }
    271 
    272  private:
    273   void OpenDexFiles(const std::vector<std::string>& dex_paths, bool open_writable) {
    274     ArtDexFileLoader dex_loader;
    275     std::string error_msg;
    276 
    277     if (open_writable) {
    278       for (const std::string& filename : dex_paths) {
    279         File fd(filename.c_str(), O_RDWR, /* check_usage= */ false);
    280         CHECK_NE(fd.Fd(), -1) << "Unable to open file '" << filename << "': " << strerror(errno);
    281 
    282         // Memory-map the dex file with MAP_SHARED flag so that changes in memory
    283         // propagate to the underlying file. We run dex file verification as if
    284         // the dex file was not in boot claass path to check basic assumptions,
    285         // such as that at most one of public/private/protected flag is set.
    286         // We do those checks here and skip them when loading the processed file
    287         // into boot class path.
    288         std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(fd.Release(),
    289                                                                    /* location= */ filename,
    290                                                                    /* verify= */ true,
    291                                                                    /* verify_checksum= */ true,
    292                                                                    /* mmap_shared= */ true,
    293                                                                    &error_msg));
    294         CHECK(dex_file.get() != nullptr) << "Open failed for '" << filename << "' " << error_msg;
    295         CHECK(dex_file->IsStandardDexFile()) << "Expected a standard dex file '" << filename << "'";
    296         CHECK(dex_file->EnableWrite())
    297             << "Failed to enable write permission for '" << filename << "'";
    298         dex_files_.push_back(std::move(dex_file));
    299       }
    300     } else {
    301       for (const std::string& filename : dex_paths) {
    302         bool success = dex_loader.Open(filename.c_str(),
    303                                        /* location= */ filename,
    304                                        /* verify= */ true,
    305                                        /* verify_checksum= */ true,
    306                                        &error_msg,
    307                                        &dex_files_);
    308         CHECK(success) << "Open failed for '" << filename << "' " << error_msg;
    309       }
    310     }
    311   }
    312 
    313   // Opened dex files. Note that these are opened as `const` but may be written into.
    314   std::vector<std::unique_ptr<const DexFile>> dex_files_;
    315 };
    316 
    317 class HierarchyClass final {
    318  public:
    319   HierarchyClass() {}
    320 
    321   void AddDexClass(const DexClass& klass) {
    322     CHECK(dex_classes_.empty() || klass.Equals(dex_classes_.front()));
    323     dex_classes_.push_back(klass);
    324   }
    325 
    326   void AddExtends(HierarchyClass& parent) {
    327     CHECK(!Contains(extends_, &parent));
    328     CHECK(!Contains(parent.extended_by_, this));
    329     extends_.push_back(&parent);
    330     parent.extended_by_.push_back(this);
    331   }
    332 
    333   const DexClass& GetOneDexClass() const {
    334     CHECK(!dex_classes_.empty());
    335     return dex_classes_.front();
    336   }
    337 
    338   // See comment on Hierarchy::ForEachResolvableMember.
    339   template<typename Fn>
    340   bool ForEachResolvableMember(const DexMember& other, Fn fn) {
    341     std::vector<HierarchyClass*> visited;
    342     return ForEachResolvableMember_Impl(other, fn, true, true, visited);
    343   }
    344 
    345   // Returns true if this class contains at least one member matching `other`.
    346   bool HasMatchingMember(const DexMember& other) {
    347     return ForEachMatchingMember(other, [](const DexMember&) { return true; });
    348   }
    349 
    350   // Recursively iterates over all subclasses of this class and invokes `fn`
    351   // on each one. If `fn` returns false for a particular subclass, exploring its
    352   // subclasses is skipped.
    353   template<typename Fn>
    354   void ForEachSubClass(Fn fn) {
    355     for (HierarchyClass* subclass : extended_by_) {
    356       if (fn(subclass)) {
    357         subclass->ForEachSubClass(fn);
    358       }
    359     }
    360   }
    361 
    362  private:
    363   template<typename Fn>
    364   bool ForEachResolvableMember_Impl(const DexMember& other,
    365                                     Fn fn,
    366                                     bool allow_explore_up,
    367                                     bool allow_explore_down,
    368                                     std::vector<HierarchyClass*> visited) {
    369     if (std::find(visited.begin(), visited.end(), this) == visited.end()) {
    370       visited.push_back(this);
    371     } else {
    372       return false;
    373     }
    374 
    375     // First try to find a member matching `other` in this class.
    376     bool found = ForEachMatchingMember(other, fn);
    377 
    378     // If not found, see if it is inherited from parents. Note that this will not
    379     // revisit parents already in `visited`.
    380     if (!found && allow_explore_up) {
    381       for (HierarchyClass* superclass : extends_) {
    382         found |= superclass->ForEachResolvableMember_Impl(
    383             other,
    384             fn,
    385             /* allow_explore_up */ true,
    386             /* allow_explore_down */ false,
    387             visited);
    388       }
    389     }
    390 
    391     // If this is a virtual method, continue exploring into subclasses so as to visit
    392     // all overriding methods. Allow subclasses to explore their superclasses if this
    393     // is an interface. This is needed to find implementations of this interface's
    394     // methods inherited from superclasses (b/122551864).
    395     if (allow_explore_down && other.IsVirtualMethod()) {
    396       for (HierarchyClass* subclass : extended_by_) {
    397         subclass->ForEachResolvableMember_Impl(
    398             other,
    399             fn,
    400             /* allow_explore_up */ GetOneDexClass().IsInterface(),
    401             /* allow_explore_down */ true,
    402             visited);
    403       }
    404     }
    405 
    406     return found;
    407   }
    408 
    409   template<typename Fn>
    410   bool ForEachMatchingMember(const DexMember& other, Fn fn) {
    411     bool found = false;
    412     auto compare_member = [&](const DexMember& member) {
    413       // TODO(dbrazdil): Check whether class of `other` can access `member`.
    414       if (member == other) {
    415         found = true;
    416         fn(member);
    417       }
    418     };
    419     for (const DexClass& dex_class : dex_classes_) {
    420       for (const ClassAccessor::Field& field : dex_class.GetFields()) {
    421         compare_member(DexMember(dex_class, field));
    422       }
    423       for (const ClassAccessor::Method& method : dex_class.GetMethods()) {
    424         compare_member(DexMember(dex_class, method));
    425       }
    426     }
    427     return found;
    428   }
    429 
    430   // DexClass entries of this class found across all the provided dex files.
    431   std::vector<DexClass> dex_classes_;
    432 
    433   // Classes which this class inherits, or interfaces which it implements.
    434   std::vector<HierarchyClass*> extends_;
    435 
    436   // Classes which inherit from this class.
    437   std::vector<HierarchyClass*> extended_by_;
    438 };
    439 
    440 class Hierarchy final {
    441  public:
    442   explicit Hierarchy(ClassPath& classpath) : classpath_(classpath) {
    443     BuildClassHierarchy();
    444   }
    445 
    446   // Perform an operation for each member of the hierarchy which could potentially
    447   // be the result of method/field resolution of `other`.
    448   // The function `fn` should accept a DexMember reference and return true if
    449   // the member was changed. This drives a performance optimization which only
    450   // visits overriding members the first time the overridden member is visited.
    451   // Returns true if at least one resolvable member was found.
    452   template<typename Fn>
    453   bool ForEachResolvableMember(const DexMember& other, Fn fn) {
    454     HierarchyClass* klass = FindClass(other.GetDeclaringClass().GetDescriptor());
    455     return (klass != nullptr) && klass->ForEachResolvableMember(other, fn);
    456   }
    457 
    458   // Returns true if `member`, which belongs to this classpath, is visible to
    459   // code in child class loaders.
    460   bool IsMemberVisible(const DexMember& member) {
    461     if (!member.IsPublicOrProtected()) {
    462       // Member is private or package-private. Cannot be visible.
    463       return false;
    464     } else if (member.GetDeclaringClass().IsPublic()) {
    465       // Member is public or protected, and class is public. It must be visible.
    466       return true;
    467     } else if (member.IsConstructor()) {
    468       // Member is public or protected constructor and class is not public.
    469       // Must be hidden because it cannot be implicitly exposed by a subclass.
    470       return false;
    471     } else {
    472       // Member is public or protected method, but class is not public. Check if
    473       // it is exposed through a public subclass.
    474       // Example code (`foo` exposed by ClassB):
    475       //   class ClassA { public void foo() { ... } }
    476       //   public class ClassB extends ClassA {}
    477       HierarchyClass* klass = FindClass(member.GetDeclaringClass().GetDescriptor());
    478       CHECK(klass != nullptr);
    479       bool visible = false;
    480       klass->ForEachSubClass([&visible, &member](HierarchyClass* subclass) {
    481         if (subclass->HasMatchingMember(member)) {
    482           // There is a member which matches `member` in `subclass`, either
    483           // a virtual method overriding `member` or a field overshadowing
    484           // `member`. In either case, `member` remains hidden.
    485           CHECK(member.IsVirtualMethod() || !member.IsMethod());
    486           return false;  // do not explore deeper
    487         } else if (subclass->GetOneDexClass().IsPublic()) {
    488           // `subclass` inherits and exposes `member`.
    489           visible = true;
    490           return false;  // do not explore deeper
    491         } else {
    492           // `subclass` inherits `member` but does not expose it.
    493           return true;   // explore deeper
    494         }
    495       });
    496       return visible;
    497     }
    498   }
    499 
    500  private:
    501   HierarchyClass* FindClass(const std::string_view& descriptor) {
    502     auto it = classes_.find(descriptor);
    503     if (it == classes_.end()) {
    504       return nullptr;
    505     } else {
    506       return &it->second;
    507     }
    508   }
    509 
    510   void BuildClassHierarchy() {
    511     // Create one HierarchyClass entry in `classes_` per class descriptor
    512     // and add all DexClass objects with the same descriptor to that entry.
    513     classpath_.ForEachDexClass([this](const DexClass& klass) {
    514       classes_[klass.GetDescriptor()].AddDexClass(klass);
    515     });
    516 
    517     // Connect each HierarchyClass to its successors and predecessors.
    518     for (auto& entry : classes_) {
    519       HierarchyClass& klass = entry.second;
    520       const DexClass& dex_klass = klass.GetOneDexClass();
    521 
    522       if (!dex_klass.HasSuperclass()) {
    523         CHECK(dex_klass.GetInterfaceDescriptors().empty())
    524             << "java/lang/Object should not implement any interfaces";
    525         continue;
    526       }
    527 
    528       HierarchyClass* superclass = FindClass(dex_klass.GetSuperclassDescriptor());
    529       CHECK(superclass != nullptr)
    530           << "Superclass " << dex_klass.GetSuperclassDescriptor()
    531           << " of class " << dex_klass.GetDescriptor() << " from dex file \""
    532           << dex_klass.GetDexFile().GetLocation() << "\" was not found. "
    533           << "Either the superclass is missing or it appears later in the classpath spec.";
    534       klass.AddExtends(*superclass);
    535 
    536       for (const std::string_view& iface_desc : dex_klass.GetInterfaceDescriptors()) {
    537         HierarchyClass* iface = FindClass(iface_desc);
    538         CHECK(iface != nullptr);
    539         klass.AddExtends(*iface);
    540       }
    541     }
    542   }
    543 
    544   ClassPath& classpath_;
    545   std::map<std::string_view, HierarchyClass> classes_;
    546 };
    547 
    548 // Builder of dex section containing hiddenapi flags.
    549 class HiddenapiClassDataBuilder final {
    550  public:
    551   explicit HiddenapiClassDataBuilder(const DexFile& dex_file)
    552       : num_classdefs_(dex_file.NumClassDefs()),
    553         next_class_def_idx_(0u),
    554         class_def_has_non_zero_flags_(false),
    555         dex_file_has_non_zero_flags_(false),
    556         data_(sizeof(uint32_t) * (num_classdefs_ + 1), 0u) {
    557     *GetSizeField() = GetCurrentDataSize();
    558   }
    559 
    560   // Notify the builder that new flags for the next class def
    561   // will be written now. The builder records the current offset
    562   // into the header.
    563   void BeginClassDef(uint32_t idx) {
    564     CHECK_EQ(next_class_def_idx_, idx);
    565     CHECK_LT(idx, num_classdefs_);
    566     GetOffsetArray()[idx] = GetCurrentDataSize();
    567     class_def_has_non_zero_flags_ = false;
    568   }
    569 
    570   // Notify the builder that all flags for this class def have been
    571   // written. The builder updates the total size of the data struct
    572   // and may set offset for class def in header to zero if no data
    573   // has been written.
    574   void EndClassDef(uint32_t idx) {
    575     CHECK_EQ(next_class_def_idx_, idx);
    576     CHECK_LT(idx, num_classdefs_);
    577 
    578     ++next_class_def_idx_;
    579 
    580     if (!class_def_has_non_zero_flags_) {
    581       // No need to store flags for this class. Remove the written flags
    582       // and set offset in header to zero.
    583       data_.resize(GetOffsetArray()[idx]);
    584       GetOffsetArray()[idx] = 0u;
    585     }
    586 
    587     dex_file_has_non_zero_flags_ |= class_def_has_non_zero_flags_;
    588 
    589     if (idx == num_classdefs_ - 1) {
    590       if (dex_file_has_non_zero_flags_) {
    591         // This was the last class def and we have generated non-zero hiddenapi
    592         // flags. Update total size in the header.
    593         *GetSizeField() = GetCurrentDataSize();
    594       } else {
    595         // This was the last class def and we have not generated any non-zero
    596         // hiddenapi flags. Clear all the data.
    597         data_.clear();
    598       }
    599     }
    600   }
    601 
    602   // Append flags at the end of the data struct. This should be called
    603   // between BeginClassDef and EndClassDef in the order of appearance of
    604   // fields/methods in the class data stream.
    605   void WriteFlags(const ApiList& flags) {
    606     uint32_t dex_flags = flags.GetDexFlags();
    607     EncodeUnsignedLeb128(&data_, dex_flags);
    608     class_def_has_non_zero_flags_ |= (dex_flags != 0u);
    609   }
    610 
    611   // Return backing data, assuming that all flags have been written.
    612   const std::vector<uint8_t>& GetData() const {
    613     CHECK_EQ(next_class_def_idx_, num_classdefs_) << "Incomplete data";
    614     return data_;
    615   }
    616 
    617  private:
    618   // Returns pointer to the size field in the header of this dex section.
    619   uint32_t* GetSizeField() {
    620     // Assume malloc() aligns allocated memory to at least uint32_t.
    621     CHECK(IsAligned<sizeof(uint32_t)>(data_.data()));
    622     return reinterpret_cast<uint32_t*>(data_.data());
    623   }
    624 
    625   // Returns pointer to array of offsets (indexed by class def indices) in the
    626   // header of this dex section.
    627   uint32_t* GetOffsetArray() { return &GetSizeField()[1]; }
    628   uint32_t GetCurrentDataSize() const { return data_.size(); }
    629 
    630   // Number of class defs in this dex file.
    631   const uint32_t num_classdefs_;
    632 
    633   // Next expected class def index.
    634   uint32_t next_class_def_idx_;
    635 
    636   // Whether non-zero flags have been encountered for this class def.
    637   bool class_def_has_non_zero_flags_;
    638 
    639   // Whether any non-zero flags have been encountered for this dex file.
    640   bool dex_file_has_non_zero_flags_;
    641 
    642   // Vector containing the data of the built data structure.
    643   std::vector<uint8_t> data_;
    644 };
    645 
    646 // Edits a dex file, inserting a new HiddenapiClassData section.
    647 class DexFileEditor final {
    648  public:
    649   DexFileEditor(const DexFile& old_dex, const std::vector<uint8_t>& hiddenapi_class_data)
    650       : old_dex_(old_dex),
    651         hiddenapi_class_data_(hiddenapi_class_data),
    652         loaded_dex_header_(nullptr),
    653         loaded_dex_maplist_(nullptr) {}
    654 
    655   // Copies dex file into a backing data vector, appends the given HiddenapiClassData
    656   // and updates the MapList.
    657   void Encode() {
    658     // We do not support non-standard dex encodings, e.g. compact dex.
    659     CHECK(old_dex_.IsStandardDexFile());
    660 
    661     // If there are no data to append, copy the old dex file and return.
    662     if (hiddenapi_class_data_.empty()) {
    663       AllocateMemory(old_dex_.Size());
    664       Append(old_dex_.Begin(), old_dex_.Size(), /* update_header= */ false);
    665       return;
    666     }
    667 
    668     // Find the old MapList, find its size.
    669     const dex::MapList* old_map = old_dex_.GetMapList();
    670     CHECK_LT(old_map->size_, std::numeric_limits<uint32_t>::max());
    671 
    672     // Compute the size of the new dex file. We append the HiddenapiClassData,
    673     // one MapItem and possibly some padding to align the new MapList.
    674     CHECK(IsAligned<kMapListAlignment>(old_dex_.Size()))
    675         << "End of input dex file is not 4-byte aligned, possibly because its MapList is not "
    676         << "at the end of the file.";
    677     size_t size_delta =
    678         RoundUp(hiddenapi_class_data_.size(), kMapListAlignment) + sizeof(dex::MapItem);
    679     size_t new_size = old_dex_.Size() + size_delta;
    680     AllocateMemory(new_size);
    681 
    682     // Copy the old dex file into the backing data vector. Load the copied
    683     // dex file to obtain pointers to its header and MapList.
    684     Append(old_dex_.Begin(), old_dex_.Size(), /* update_header= */ false);
    685     ReloadDex(/* verify= */ false);
    686 
    687     // Truncate the new dex file before the old MapList. This assumes that
    688     // the MapList is the last entry in the dex file. This is currently true
    689     // for our tooling.
    690     // TODO: Implement the general case by zero-ing the old MapList (turning
    691     // it into padding.
    692     RemoveOldMapList();
    693 
    694     // Append HiddenapiClassData.
    695     size_t payload_offset = AppendHiddenapiClassData();
    696 
    697     // Wrute new MapList with an entry for HiddenapiClassData.
    698     CreateMapListWithNewItem(payload_offset);
    699 
    700     // Check that the pre-computed size matches the actual size.
    701     CHECK_EQ(offset_, new_size);
    702 
    703     // Reload to all data structures.
    704     ReloadDex(/* verify= */ false);
    705 
    706     // Update the dex checksum.
    707     UpdateChecksum();
    708 
    709     // Run DexFileVerifier on the new dex file as a CHECK.
    710     ReloadDex(/* verify= */ true);
    711   }
    712 
    713   // Writes the edited dex file into a file.
    714   void WriteTo(const std::string& path) {
    715     CHECK(!data_.empty());
    716     std::ofstream ofs(path.c_str(), std::ofstream::out | std::ofstream::binary);
    717     ofs.write(reinterpret_cast<const char*>(data_.data()), data_.size());
    718     ofs.flush();
    719     CHECK(ofs.good());
    720     ofs.close();
    721   }
    722 
    723  private:
    724   static constexpr size_t kMapListAlignment = 4u;
    725   static constexpr size_t kHiddenapiClassDataAlignment = 4u;
    726 
    727   void ReloadDex(bool verify) {
    728     std::string error_msg;
    729     DexFileLoader loader;
    730     loaded_dex_ = loader.Open(
    731         data_.data(),
    732         data_.size(),
    733         "test_location",
    734         old_dex_.GetLocationChecksum(),
    735         /* oat_dex_file= */ nullptr,
    736         /* verify= */ verify,
    737         /* verify_checksum= */ verify,
    738         &error_msg);
    739     if (loaded_dex_.get() == nullptr) {
    740       LOG(FATAL) << "Failed to load edited dex file: " << error_msg;
    741       UNREACHABLE();
    742     }
    743 
    744     // Load the location of header and map list before we start editing the file.
    745     loaded_dex_header_ = const_cast<DexFile::Header*>(&loaded_dex_->GetHeader());
    746     loaded_dex_maplist_ = const_cast<dex::MapList*>(loaded_dex_->GetMapList());
    747   }
    748 
    749   DexFile::Header& GetHeader() const {
    750     CHECK(loaded_dex_header_ != nullptr);
    751     return *loaded_dex_header_;
    752   }
    753 
    754   dex::MapList& GetMapList() const {
    755     CHECK(loaded_dex_maplist_ != nullptr);
    756     return *loaded_dex_maplist_;
    757   }
    758 
    759   void AllocateMemory(size_t total_size) {
    760     data_.clear();
    761     data_.resize(total_size);
    762     CHECK(IsAligned<kMapListAlignment>(data_.data()));
    763     CHECK(IsAligned<kHiddenapiClassDataAlignment>(data_.data()));
    764     offset_ = 0;
    765   }
    766 
    767   uint8_t* GetCurrentDataPtr() {
    768     return data_.data() + offset_;
    769   }
    770 
    771   void UpdateDataSize(off_t delta, bool update_header) {
    772     offset_ += delta;
    773     if (update_header) {
    774       DexFile::Header& header = GetHeader();
    775       header.file_size_ += delta;
    776       header.data_size_ += delta;
    777     }
    778   }
    779 
    780   template<typename T>
    781   T* Append(const T* src, size_t len, bool update_header = true) {
    782     CHECK_LE(offset_ + len, data_.size());
    783     uint8_t* dst = GetCurrentDataPtr();
    784     memcpy(dst, src, len);
    785     UpdateDataSize(len, update_header);
    786     return reinterpret_cast<T*>(dst);
    787   }
    788 
    789   void InsertPadding(size_t alignment) {
    790     size_t len = RoundUp(offset_, alignment) - offset_;
    791     std::vector<uint8_t> padding(len, 0);
    792     Append(padding.data(), padding.size());
    793   }
    794 
    795   void RemoveOldMapList() {
    796     size_t map_size = GetMapList().Size();
    797     uint8_t* map_start = reinterpret_cast<uint8_t*>(&GetMapList());
    798     CHECK_EQ(map_start + map_size, GetCurrentDataPtr()) << "MapList not at the end of dex file";
    799     UpdateDataSize(-static_cast<off_t>(map_size), /* update_header= */ true);
    800     CHECK_EQ(map_start, GetCurrentDataPtr());
    801     loaded_dex_maplist_ = nullptr;  // do not use this map list any more
    802   }
    803 
    804   void CreateMapListWithNewItem(size_t payload_offset) {
    805     InsertPadding(/* alignment= */ kMapListAlignment);
    806 
    807     size_t new_map_offset = offset_;
    808     dex::MapList* map = Append(old_dex_.GetMapList(), old_dex_.GetMapList()->Size());
    809 
    810     // Check last map entry is a pointer to itself.
    811     dex::MapItem& old_item = map->list_[map->size_ - 1];
    812     CHECK(old_item.type_ == DexFile::kDexTypeMapList);
    813     CHECK_EQ(old_item.size_, 1u);
    814     CHECK_EQ(old_item.offset_, GetHeader().map_off_);
    815 
    816     // Create a new MapItem entry with new MapList details.
    817     dex::MapItem new_item;
    818     new_item.type_ = old_item.type_;
    819     new_item.unused_ = 0u;  // initialize to ensure dex output is deterministic (b/119308882)
    820     new_item.size_ = old_item.size_;
    821     new_item.offset_ = new_map_offset;
    822 
    823     // Update pointer in the header.
    824     GetHeader().map_off_ = new_map_offset;
    825 
    826     // Append a new MapItem and return its pointer.
    827     map->size_++;
    828     Append(&new_item, sizeof(dex::MapItem));
    829 
    830     // Change penultimate entry to point to metadata.
    831     old_item.type_ = DexFile::kDexTypeHiddenapiClassData;
    832     old_item.size_ = 1u;  // there is only one section
    833     old_item.offset_ = payload_offset;
    834   }
    835 
    836   size_t AppendHiddenapiClassData() {
    837     size_t payload_offset = offset_;
    838     CHECK_EQ(kMapListAlignment, kHiddenapiClassDataAlignment);
    839     CHECK(IsAligned<kHiddenapiClassDataAlignment>(payload_offset))
    840         << "Should not need to align the section, previous data was already aligned";
    841     Append(hiddenapi_class_data_.data(), hiddenapi_class_data_.size());
    842     return payload_offset;
    843   }
    844 
    845   void UpdateChecksum() {
    846     GetHeader().checksum_ = loaded_dex_->CalculateChecksum();
    847   }
    848 
    849   const DexFile& old_dex_;
    850   const std::vector<uint8_t>& hiddenapi_class_data_;
    851 
    852   std::vector<uint8_t> data_;
    853   size_t offset_;
    854 
    855   std::unique_ptr<const DexFile> loaded_dex_;
    856   DexFile::Header* loaded_dex_header_;
    857   dex::MapList* loaded_dex_maplist_;
    858 };
    859 
    860 class HiddenApi final {
    861  public:
    862   HiddenApi() : force_assign_all_(true) {}
    863 
    864   void Run(int argc, char** argv) {
    865     switch (ParseArgs(argc, argv)) {
    866     case Command::kEncode:
    867       EncodeAccessFlags();
    868       break;
    869     case Command::kList:
    870       ListApi();
    871       break;
    872     }
    873   }
    874 
    875  private:
    876   enum class Command {
    877     kEncode,
    878     kList,
    879   };
    880 
    881   Command ParseArgs(int argc, char** argv) {
    882     // Skip over the binary's path.
    883     argv++;
    884     argc--;
    885 
    886     if (argc > 0) {
    887       const char* raw_command = argv[0];
    888       const std::string_view command(raw_command);
    889       if (command == "encode") {
    890         for (int i = 1; i < argc; ++i) {
    891           const char* raw_option = argv[i];
    892           const std::string_view option(raw_option);
    893           if (StartsWith(option, "--input-dex=")) {
    894             boot_dex_paths_.push_back(std::string(option.substr(strlen("--input-dex="))));
    895           } else if (StartsWith(option, "--output-dex=")) {
    896             output_dex_paths_.push_back(std::string(option.substr(strlen("--output-dex="))));
    897           } else if (StartsWith(option, "--api-flags=")) {
    898             api_flags_path_ = std::string(option.substr(strlen("--api-flags=")));
    899           } else if (option == "--no-force-assign-all") {
    900             force_assign_all_ = false;
    901           } else {
    902             Usage("Unknown argument '%s'", raw_option);
    903           }
    904         }
    905         return Command::kEncode;
    906       } else if (command == "list") {
    907         for (int i = 1; i < argc; ++i) {
    908           const char* raw_option = argv[i];
    909           const std::string_view option(raw_option);
    910           if (StartsWith(option, "--boot-dex=")) {
    911             boot_dex_paths_.push_back(std::string(option.substr(strlen("--boot-dex="))));
    912           } else if (StartsWith(option, "--public-stub-classpath=")) {
    913             stub_classpaths_.push_back(std::make_pair(
    914                 std::string(option.substr(strlen("--public-stub-classpath="))),
    915                 ApiStubs::Kind::kPublicApi));
    916           } else if (StartsWith(option, "--system-stub-classpath=")) {
    917             stub_classpaths_.push_back(std::make_pair(
    918                 std::string(option.substr(strlen("--system-stub-classpath="))),
    919                 ApiStubs::Kind::kSystemApi));
    920           } else if (StartsWith(option, "--test-stub-classpath=")) {
    921             stub_classpaths_.push_back(std::make_pair(
    922                 std::string(option.substr(strlen("--test-stub-classpath="))),
    923                 ApiStubs::Kind::kTestApi));
    924           } else if (StartsWith(option, "--core-platform-stub-classpath=")) {
    925             stub_classpaths_.push_back(std::make_pair(
    926                 std::string(option.substr(strlen("--core-platform-stub-classpath="))),
    927                 ApiStubs::Kind::kCorePlatformApi));
    928           } else if (StartsWith(option, "--out-api-flags=")) {
    929             api_flags_path_ = std::string(option.substr(strlen("--out-api-flags=")));
    930           } else {
    931             Usage("Unknown argument '%s'", raw_option);
    932           }
    933         }
    934         return Command::kList;
    935       } else {
    936         Usage("Unknown command '%s'", raw_command);
    937       }
    938     } else {
    939       Usage("No command specified");
    940     }
    941   }
    942 
    943   void EncodeAccessFlags() {
    944     if (boot_dex_paths_.empty()) {
    945       Usage("No input DEX files specified");
    946     } else if (output_dex_paths_.size() != boot_dex_paths_.size()) {
    947       Usage("Number of input DEX files does not match number of output DEX files");
    948     }
    949 
    950     // Load dex signatures.
    951     std::map<std::string, ApiList> api_list = OpenApiFile(api_flags_path_);
    952 
    953     // Iterate over input dex files and insert HiddenapiClassData sections.
    954     for (size_t i = 0; i < boot_dex_paths_.size(); ++i) {
    955       const std::string& input_path = boot_dex_paths_[i];
    956       const std::string& output_path = output_dex_paths_[i];
    957 
    958       ClassPath boot_classpath({ input_path }, /* open_writable= */ false);
    959       std::vector<const DexFile*> input_dex_files = boot_classpath.GetDexFiles();
    960       CHECK_EQ(input_dex_files.size(), 1u);
    961       const DexFile& input_dex = *input_dex_files[0];
    962 
    963       HiddenapiClassDataBuilder builder(input_dex);
    964       boot_classpath.ForEachDexClass([&](const DexClass& boot_class) {
    965         builder.BeginClassDef(boot_class.GetClassDefIndex());
    966         if (boot_class.GetData() != nullptr) {
    967           auto fn_shared = [&](const DexMember& boot_member) {
    968             auto it = api_list.find(boot_member.GetApiEntry());
    969             bool api_list_found = (it != api_list.end());
    970             CHECK(!force_assign_all_ || api_list_found)
    971                 << "Could not find hiddenapi flags for dex entry: " << boot_member.GetApiEntry();
    972             builder.WriteFlags(api_list_found ? it->second : ApiList::Whitelist());
    973           };
    974           auto fn_field = [&](const ClassAccessor::Field& boot_field) {
    975             fn_shared(DexMember(boot_class, boot_field));
    976           };
    977           auto fn_method = [&](const ClassAccessor::Method& boot_method) {
    978             fn_shared(DexMember(boot_class, boot_method));
    979           };
    980           boot_class.VisitFieldsAndMethods(fn_field, fn_field, fn_method, fn_method);
    981         }
    982         builder.EndClassDef(boot_class.GetClassDefIndex());
    983       });
    984 
    985       DexFileEditor dex_editor(input_dex, builder.GetData());
    986       dex_editor.Encode();
    987       dex_editor.WriteTo(output_path);
    988     }
    989   }
    990 
    991   std::map<std::string, ApiList> OpenApiFile(const std::string& path) {
    992     CHECK(!path.empty());
    993     std::ifstream api_file(path, std::ifstream::in);
    994     CHECK(!api_file.fail()) << "Unable to open file '" << path << "' " << strerror(errno);
    995 
    996     std::map<std::string, ApiList> api_flag_map;
    997 
    998     size_t line_number = 1;
    999     for (std::string line; std::getline(api_file, line); line_number++) {
   1000       // Every line contains a comma separated list with the signature as the
   1001       // first element and the api flags as the rest
   1002       std::vector<std::string> values = android::base::Split(line, ",");
   1003       CHECK_GT(values.size(), 1u) << path << ":" << line_number
   1004           << ": No flags found: " << line << kErrorHelp;
   1005 
   1006       const std::string& signature = values[0];
   1007 
   1008       CHECK(api_flag_map.find(signature) == api_flag_map.end()) << path << ":" << line_number
   1009           << ": Duplicate entry: " << signature << kErrorHelp;
   1010 
   1011       ApiList membership;
   1012 
   1013       bool success = ApiList::FromNames(values.begin() + 1, values.end(), &membership);
   1014       CHECK(success) << path << ":" << line_number
   1015           << ": Some flags were not recognized: " << line << kErrorHelp;
   1016       CHECK(membership.IsValid()) << path << ":" << line_number
   1017           << ": Invalid combination of flags: " << line << kErrorHelp;
   1018 
   1019       api_flag_map.emplace(signature, membership);
   1020     }
   1021 
   1022     api_file.close();
   1023     return api_flag_map;
   1024   }
   1025 
   1026   void ListApi() {
   1027     if (boot_dex_paths_.empty()) {
   1028       Usage("No boot DEX files specified");
   1029     } else if (stub_classpaths_.empty()) {
   1030       Usage("No stub DEX files specified");
   1031     } else if (api_flags_path_.empty()) {
   1032       Usage("No output path specified");
   1033     }
   1034 
   1035     // Complete list of boot class path members. The associated boolean states
   1036     // whether it is public (true) or private (false).
   1037     std::map<std::string, std::set<std::string_view>> boot_members;
   1038 
   1039     // Deduplicate errors before printing them.
   1040     std::set<std::string> unresolved;
   1041 
   1042     // Open all dex files.
   1043     ClassPath boot_classpath(boot_dex_paths_, /* open_writable= */ false);
   1044     Hierarchy boot_hierarchy(boot_classpath);
   1045 
   1046     // Mark all boot dex members private.
   1047     boot_classpath.ForEachDexMember([&](const DexMember& boot_member) {
   1048       boot_members[boot_member.GetApiEntry()] = {};
   1049     });
   1050 
   1051     // Resolve each SDK dex member against the framework and mark it white.
   1052     for (const auto& cp_entry : stub_classpaths_) {
   1053       ClassPath stub_classpath(android::base::Split(cp_entry.first, ":"),
   1054                                /* open_writable= */ false);
   1055       Hierarchy stub_hierarchy(stub_classpath);
   1056       const ApiStubs::Kind stub_api = cp_entry.second;
   1057 
   1058       stub_classpath.ForEachDexMember(
   1059           [&](const DexMember& stub_member) {
   1060             if (!stub_hierarchy.IsMemberVisible(stub_member)) {
   1061               // Typically fake constructors and inner-class `this` fields.
   1062               return;
   1063             }
   1064             bool resolved = boot_hierarchy.ForEachResolvableMember(
   1065                 stub_member,
   1066                 [&](const DexMember& boot_member) {
   1067                   std::string entry = boot_member.GetApiEntry();
   1068                   auto it = boot_members.find(entry);
   1069                   CHECK(it != boot_members.end());
   1070                   it->second.insert(ApiStubs::ToString(stub_api));
   1071                 });
   1072             if (!resolved) {
   1073               unresolved.insert(stub_member.GetApiEntry());
   1074             }
   1075           });
   1076     }
   1077 
   1078     // Print errors.
   1079     for (const std::string& str : unresolved) {
   1080       LOG(WARNING) << "unresolved: " << str;
   1081     }
   1082 
   1083     // Write into public/private API files.
   1084     std::ofstream file_flags(api_flags_path_.c_str());
   1085     for (const auto& entry : boot_members) {
   1086       if (entry.second.empty()) {
   1087         file_flags << entry.first << std::endl;
   1088       } else {
   1089         file_flags << entry.first << ",";
   1090         file_flags << android::base::Join(entry.second, ",") << std::endl;
   1091       }
   1092     }
   1093     file_flags.close();
   1094   }
   1095 
   1096   // Whether to check that all dex entries have been assigned flags.
   1097   // Defaults to true.
   1098   bool force_assign_all_;
   1099 
   1100   // Paths to DEX files which should be processed.
   1101   std::vector<std::string> boot_dex_paths_;
   1102 
   1103   // Output paths where modified DEX files should be written.
   1104   std::vector<std::string> output_dex_paths_;
   1105 
   1106   // Set of public API stub classpaths. Each classpath is formed by a list
   1107   // of DEX/APK files in the order they appear on the classpath.
   1108   std::vector<std::pair<std::string, ApiStubs::Kind>> stub_classpaths_;
   1109 
   1110   // Path to CSV file containing the list of API members and their flags.
   1111   // This could be both an input and output path.
   1112   std::string api_flags_path_;
   1113 };
   1114 
   1115 }  // namespace hiddenapi
   1116 }  // namespace art
   1117 
   1118 int main(int argc, char** argv) {
   1119   art::hiddenapi::original_argc = argc;
   1120   art::hiddenapi::original_argv = argv;
   1121   android::base::InitLogging(argv);
   1122   art::MemMap::Init();
   1123   art::hiddenapi::HiddenApi().Run(argc, argv);
   1124   return EXIT_SUCCESS;
   1125 }
   1126