diff options
Diffstat (limited to 'tools/hiddenapi/hiddenapi.cc')
-rw-r--r-- | tools/hiddenapi/hiddenapi.cc | 120 |
1 files changed, 50 insertions, 70 deletions
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index f426d02c5b..2692f6811a 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -124,6 +124,7 @@ class DexClass : public ClassAccessor { } inline bool IsPublic() const { return HasAccessFlags(kAccPublic); } + inline bool IsInterface() const { return HasAccessFlags(kAccInterface); } inline bool Equals(const DexClass& other) const { bool equals = strcmp(GetDescriptor(), other.GetDescriptor()) == 0; @@ -344,13 +345,13 @@ class HierarchyClass final { // See comment on Hierarchy::ForEachResolvableMember. template<typename Fn> bool ForEachResolvableMember(const DexMember& other, Fn fn) { - return ForEachResolvableMember_Impl(other, fn) != ResolutionResult::kNotFound; + std::vector<HierarchyClass*> visited; + return ForEachResolvableMember_Impl(other, fn, true, true, visited); } // Returns true if this class contains at least one member matching `other`. bool HasMatchingMember(const DexMember& other) { - return ForEachMatchingMember( - other, [](const DexMember&) { return true; }) != ResolutionResult::kNotFound; + return ForEachMatchingMember(other, [](const DexMember&) { return true; }); } // Recursively iterates over all subclasses of this class and invokes `fn` @@ -366,62 +367,60 @@ class HierarchyClass final { } private: - // Result of resolution which takes into account whether the member was found - // for the first time or not. This is just a performance optimization to prevent - // re-visiting previously visited members. - // Note that order matters. When accumulating results, we always pick the maximum. - enum class ResolutionResult { - kNotFound, - kFoundOld, - kFoundNew, - }; - - inline ResolutionResult Accumulate(ResolutionResult a, ResolutionResult b) { - return static_cast<ResolutionResult>( - std::max(static_cast<unsigned>(a), static_cast<unsigned>(b))); - } - template<typename Fn> - ResolutionResult ForEachResolvableMember_Impl(const DexMember& other, Fn fn) { + bool ForEachResolvableMember_Impl(const DexMember& other, + Fn fn, + bool allow_explore_up, + bool allow_explore_down, + std::vector<HierarchyClass*> visited) { + if (std::find(visited.begin(), visited.end(), this) == visited.end()) { + visited.push_back(this); + } else { + return false; + } + // First try to find a member matching `other` in this class. - ResolutionResult foundInClass = ForEachMatchingMember(other, fn); - - switch (foundInClass) { - case ResolutionResult::kFoundOld: - // A matching member was found and previously explored. All subclasses - // must have been explored too. - break; - - case ResolutionResult::kFoundNew: - // A matching member was found and this was the first time it was visited. - // If it is a virtual method, visit all methods overriding/implementing it too. - if (other.IsVirtualMethod()) { - for (HierarchyClass* subclass : extended_by_) { - subclass->ForEachOverridingMember(other, fn); - } - } - break; - - case ResolutionResult::kNotFound: - // A matching member was not found in this class. Explore the superclasses - // and implemented interfaces. - for (HierarchyClass* superclass : extends_) { - foundInClass = Accumulate( - foundInClass, superclass->ForEachResolvableMember_Impl(other, fn)); - } - break; + bool found = ForEachMatchingMember(other, fn); + + // If not found, see if it is inherited from parents. Note that this will not + // revisit parents already in `visited`. + if (!found && allow_explore_up) { + for (HierarchyClass* superclass : extends_) { + found |= superclass->ForEachResolvableMember_Impl( + other, + fn, + /* allow_explore_up */ true, + /* allow_explore_down */ false, + visited); + } } - return foundInClass; + // If this is a virtual method, continue exploring into subclasses so as to visit + // all overriding methods. Allow subclasses to explore their superclasses if this + // is an interface. This is needed to find implementations of this interface's + // methods inherited from superclasses (b/122551864). + if (allow_explore_down && other.IsVirtualMethod()) { + for (HierarchyClass* subclass : extended_by_) { + subclass->ForEachResolvableMember_Impl( + other, + fn, + /* allow_explore_up */ GetOneDexClass().IsInterface(), + /* allow_explore_down */ true, + visited); + } + } + + return found; } template<typename Fn> - ResolutionResult ForEachMatchingMember(const DexMember& other, Fn fn) { - ResolutionResult found = ResolutionResult::kNotFound; + bool ForEachMatchingMember(const DexMember& other, Fn fn) { + bool found = false; auto compare_member = [&](const DexMember& member) { + // TODO(dbrazdil): Check whether class of `other` can access `member`. if (member == other) { - found = Accumulate(found, fn(member) ? ResolutionResult::kFoundNew - : ResolutionResult::kFoundOld); + found = true; + fn(member); } }; for (const DexClass& dex_class : dex_classes_) { @@ -435,20 +434,6 @@ class HierarchyClass final { return found; } - template<typename Fn> - void ForEachOverridingMember(const DexMember& other, Fn fn) { - CHECK(other.IsVirtualMethod()); - ResolutionResult found = ForEachMatchingMember(other, fn); - if (found == ResolutionResult::kFoundOld) { - // No need to explore further. - return; - } else { - for (HierarchyClass* subclass : extended_by_) { - subclass->ForEachOverridingMember(other, fn); - } - } - } - // DexClass entries of this class found across all the provided dex files. std::vector<DexClass> dex_classes_; @@ -1070,12 +1055,7 @@ class HiddenApi final { std::string entry = boot_member.GetApiEntry(); auto it = boot_members.find(entry); CHECK(it != boot_members.end()); - if (it->second.Contains(stub_api_list)) { - return false; // has been marked before - } else { - it->second |= stub_api_list; - return true; // marked for the first time - } + it->second |= stub_api_list; }); if (!resolved) { unresolved.insert(stub_member.GetApiEntry()); |