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