summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Android.mk2
-rw-r--r--tools/art_verifier/Android.bp48
-rw-r--r--tools/art_verifier/art_verifier.cc267
-rw-r--r--tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java9
-rw-r--r--tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java137
-rw-r--r--tools/hiddenapi/hiddenapi.cc154
-rw-r--r--tools/jfuzz/jfuzz.cc2
-rw-r--r--tools/libcore_gcstress_debug_failures.txt3
-rw-r--r--tools/libcore_gcstress_failures.txt34
-rwxr-xr-xtools/run-libcore-tests.sh6
-rw-r--r--tools/veridex/flow_analysis.cc8
-rw-r--r--tools/veridex/flow_analysis.h16
-rw-r--r--tools/veridex/hidden_api_finder.cc42
-rw-r--r--tools/veridex/precise_hidden_api_finder.cc37
-rw-r--r--tools/veridex/precise_hidden_api_finder.h2
-rw-r--r--tools/veridex/resolver.cc91
16 files changed, 682 insertions, 176 deletions
diff --git a/tools/Android.mk b/tools/Android.mk
index 9ecf0cd7ed..e90f5f5b45 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -32,3 +32,5 @@ LOCAL_MODULE := art-script
LOCAL_SRC_FILES := art
LOCAL_MODULE_STEM := art
include $(BUILD_PREBUILT)
+
+include $(LOCAL_PATH)/class2greylist/test/Android.mk
diff --git a/tools/art_verifier/Android.bp b/tools/art_verifier/Android.bp
new file mode 100644
index 0000000000..afd52fbcaa
--- /dev/null
+++ b/tools/art_verifier/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+art_cc_defaults {
+ name: "art_verifier-defaults",
+ defaults: ["art_defaults"],
+ host_supported: true,
+ srcs: [
+ "art_verifier.cc",
+ ],
+ header_libs: [
+ "art_cmdlineparser_headers",
+ ],
+ static_libs: art_static_dependencies + [
+ "libart",
+ "libartbase",
+ "libdexfile",
+ "libprofile",
+ ],
+ target: {
+ android: {
+ static_libs: [
+ "libtombstoned_client_static",
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+art_cc_binary {
+ name: "art_verifier",
+ defaults: ["art_verifier-defaults"],
+}
diff --git a/tools/art_verifier/art_verifier.cc b/tools/art_verifier/art_verifier.cc
new file mode 100644
index 0000000000..fc62410889
--- /dev/null
+++ b/tools/art_verifier/art_verifier.cc
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <vector>
+
+#include "android-base/logging.h"
+
+#include "base/logging.h"
+#include "base/os.h"
+#include "class_linker-inl.h"
+#include "dex/art_dex_file_loader.h"
+#include "dex/class_accessor-inl.h"
+#include "dex/dex_file-inl.h"
+#include "interpreter/unstarted_runtime.h"
+#include "mirror/class-inl.h"
+#include "mirror/dex_cache-inl.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+#include "verifier/method_verifier.h"
+#include "well_known_classes.h"
+
+#include <sys/stat.h>
+#include "cmdline.h"
+
+namespace art {
+
+namespace {
+
+bool LoadDexFile(const std::string& dex_filename,
+ std::vector<std::unique_ptr<const DexFile>>* dex_files) {
+ const ArtDexFileLoader dex_file_loader;
+ std::string error_msg;
+ if (!dex_file_loader.Open(dex_filename.c_str(),
+ dex_filename.c_str(),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_msg,
+ dex_files)) {
+ LOG(ERROR) << error_msg;
+ return false;
+ }
+ return true;
+}
+
+jobject Install(Runtime* runtime,
+ std::vector<std::unique_ptr<const DexFile>>& in,
+ std::vector<const DexFile*>* out)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ CHECK(self != nullptr);
+
+ // Need well-known-classes.
+ WellKnownClasses::Init(self->GetJniEnv());
+ // Need a class loader. Fake that we're a compiler.
+ // Note: this will run initializers through the unstarted runtime, so make sure it's
+ // initialized.
+ interpreter::UnstartedRuntime::Initialize();
+
+ for (std::unique_ptr<const DexFile>& dex_file : in) {
+ out->push_back(dex_file.release());
+ }
+
+ ClassLinker* class_linker = runtime->GetClassLinker();
+
+ jobject class_loader = class_linker->CreatePathClassLoader(self, *out);
+
+ // Need to register dex files to get a working dex cache.
+ for (const DexFile* dex_file : *out) {
+ ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile(
+ *dex_file, self->DecodeJObject(class_loader)->AsClassLoader());
+ CHECK(dex_cache != nullptr);
+ }
+
+ return class_loader;
+}
+
+struct MethodVerifierArgs : public CmdlineArgs {
+ protected:
+ using Base = CmdlineArgs;
+
+ virtual ParseStatus ParseCustom(const StringPiece& option,
+ std::string* error_msg) OVERRIDE {
+ {
+ ParseStatus base_parse = Base::ParseCustom(option, error_msg);
+ if (base_parse != kParseUnknownArgument) {
+ return base_parse;
+ }
+ }
+
+ if (option.starts_with("--dex-file=")) {
+ dex_filename_ = option.substr(strlen("--dex-file=")).data();
+ } else if (option == "--dex-file-verifier") {
+ dex_file_verifier_ = true;
+ } else if (option == "--verbose") {
+ method_verifier_verbose_ = true;
+ } else if (option == "--verbose-debug") {
+ method_verifier_verbose_debug_ = true;
+ } else if (option.starts_with("--repetitions=")) {
+ char* end;
+ repetitions_ = strtoul(option.substr(strlen("--repetitions=")).data(), &end, 10);
+ } else {
+ return kParseUnknownArgument;
+ }
+
+ return kParseOk;
+ }
+
+ virtual ParseStatus ParseChecks(std::string* error_msg) OVERRIDE {
+ // Perform the parent checks.
+ ParseStatus parent_checks = Base::ParseChecks(error_msg);
+ if (parent_checks != kParseOk) {
+ return parent_checks;
+ }
+
+ // Perform our own checks.
+ if (dex_filename_ == nullptr) {
+ *error_msg = "--dex-filename not set";
+ return kParseError;
+ }
+
+ return kParseOk;
+ }
+
+ virtual std::string GetUsage() const {
+ std::string usage;
+
+ usage +=
+ "Usage: method_verifier_cmd [options] ...\n"
+ // Dex file is required.
+ " --dex-file=<file.dex>: specifies an input dex file.\n"
+ " Example: --dex-file=app.apk\n"
+ " --dex-file-verifier: only run dex file verifier.\n"
+ " --verbose: use verbose verifier mode.\n"
+ " --verbose-debug: use verbose verifier debug mode.\n"
+ " --repetitions=<count>: repeat the verification count times.\n"
+ "\n";
+
+ usage += Base::GetUsage();
+
+ return usage;
+ }
+
+ public:
+ const char* dex_filename_ = nullptr;
+
+ bool dex_file_verifier_ = false;
+
+ bool method_verifier_verbose_ = false;
+ bool method_verifier_verbose_debug_ = false;
+
+ size_t repetitions_ = 0u;
+};
+
+struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> {
+ bool NeedsRuntime() OVERRIDE {
+ return true;
+ }
+
+ bool ExecuteWithoutRuntime() OVERRIDE {
+ LOG(FATAL) << "Unreachable";
+ UNREACHABLE();
+ }
+
+ bool ExecuteWithRuntime(Runtime* runtime) OVERRIDE {
+ CHECK(args_ != nullptr);
+
+ const size_t dex_reps = args_->dex_file_verifier_
+ // If we're focused on the dex file verifier, use the
+ // repetitions parameter.
+ ? std::max(static_cast<size_t>(1u), args_->repetitions_)
+ // Otherwise just load the dex files once.
+ : 1;
+
+ std::vector<std::unique_ptr<const DexFile>> unique_dex_files;
+ for (size_t i = 0; i != dex_reps; ++i) {
+ if (args_->dex_file_verifier_ && args_->repetitions_ != 0) {
+ LOG(INFO) << "Repetition " << (i + 1);
+ }
+ unique_dex_files.clear();
+ if (!LoadDexFile(args_->dex_filename_, &unique_dex_files)) {
+ return false;
+ }
+ }
+ if (args_->dex_file_verifier_) {
+ // We're done here.
+ return true;
+ }
+
+ ScopedObjectAccess soa(Thread::Current());
+ std::vector<const DexFile*> dex_files;
+ jobject class_loader = Install(runtime, unique_dex_files, &dex_files);
+ CHECK(class_loader != nullptr);
+
+ StackHandleScope<2> scope(soa.Self());
+ Handle<mirror::ClassLoader> h_loader = scope.NewHandle(
+ soa.Decode<mirror::ClassLoader>(class_loader));
+ MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
+
+ if (args_->method_verifier_verbose_) {
+ gLogVerbosity.verifier = true;
+ }
+ if (args_->method_verifier_verbose_debug_) {
+ gLogVerbosity.verifier_debug = true;
+ }
+
+ const size_t verifier_reps = std::max(static_cast<size_t>(1u), args_->repetitions_);
+
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ for (size_t i = 0; i != verifier_reps; ++i) {
+ if (args_->repetitions_ != 0) {
+ LOG(INFO) << "Repetition " << (i + 1);
+ }
+ for (const DexFile* dex_file : dex_files) {
+ for (ClassAccessor accessor : dex_file->GetClasses()) {
+ const char* descriptor = accessor.GetDescriptor();
+ h_klass.Assign(class_linker->FindClass(soa.Self(), descriptor, h_loader));
+ if (h_klass == nullptr || h_klass->IsErroneous()) {
+ if (args_->repetitions_ == 0) {
+ LOG(ERROR) << "Warning: could not load " << descriptor;
+ }
+ soa.Self()->ClearException();
+ continue;
+ }
+ std::string error_msg;
+ verifier::FailureKind res =
+ verifier::MethodVerifier::VerifyClass(soa.Self(),
+ h_klass.Get(),
+ runtime->GetCompilerCallbacks(),
+ true,
+ verifier::HardFailLogMode::kLogWarning,
+ &error_msg);
+ if (args_->repetitions_ == 0) {
+ LOG(INFO) << descriptor << ": " << res << " " << error_msg;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+};
+
+} // namespace
+
+} // namespace art
+
+int main(int argc, char** argv) {
+ // Output all logging to stderr.
+ android::base::SetLogger(android::base::StderrLogger);
+
+ art::MethodVerifierMain main;
+ return main.Main(argc, argv);
+}
diff --git a/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java b/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java
index 66857525aa..6b9ef161eb 100644
--- a/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java
+++ b/tools/class2greylist/src/com/android/class2greylist/AnnotationVisitor.java
@@ -81,14 +81,19 @@ public class AnnotationVisitor extends EmptyVisitor {
mStatus.debug("Visit member %s : %s", member.getName(), member.getSignature());
for (AnnotationEntry a : member.getAnnotationEntries()) {
if (mAnnotationType.equals(a.getAnnotationType())) {
- mStatus.debug("Method has annotation %s", mAnnotationType);
+ mStatus.debug("Member has annotation %s", mAnnotationType);
+ boolean bridge = (member.getAccessFlags() & Const.ACC_BRIDGE) != 0;
+ if (bridge) {
+ mStatus.debug("Member is a bridge", mAnnotationType);
+ }
String signature = String.format(Locale.US, signatureFormatString,
getClassDescriptor(definingClass), member.getName(), member.getSignature());
for (ElementValuePair property : a.getElementValuePairs()) {
switch (property.getNameString()) {
case EXPECTED_SIGNATURE:
String expected = property.getValue().stringifyValue();
- if (!signature.equals(expected)) {
+ // Don't enforce for bridge methods; they're generated so won't match.
+ if (!bridge && !signature.equals(expected)) {
error(definingClass, member,
"Expected signature does not match generated:\n"
+ "Expected: %s\n"
diff --git a/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java b/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java
index 2d9721803c..a4ad20c605 100644
--- a/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java
+++ b/tools/class2greylist/test/src/com/android/javac/AnnotationVisitorTest.java
@@ -19,20 +19,22 @@ package com.android.javac;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.MockitoAnnotations.initMocks;
+import static org.mockito.Mockito.withSettings;
-import com.android.class2greylist.Status;
import com.android.class2greylist.AnnotationVisitor;
+import com.android.class2greylist.Status;
import com.google.common.base.Joiner;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
import java.io.IOException;
@@ -40,13 +42,17 @@ public class AnnotationVisitorTest {
private static final String ANNOTATION = "Lannotation/Anno;";
+ @Rule
+ public TestName mTestName = new TestName();
+
private Javac mJavac;
- @Mock
private Status mStatus;
@Before
public void setup() throws IOException {
- initMocks(this);
+ System.out.println(String.format("\n============== STARTING TEST: %s ==============\n",
+ mTestName.getMethodName()));
+ mStatus = mock(Status.class, withSettings().verboseLogging());
mJavac = new Javac();
mJavac.addSource("annotation.Anno", Joiner.on('\n').join(
"package annotation;",
@@ -199,4 +205,125 @@ public class AnnotationVisitorTest {
verify(mStatus, never()).greylistEntry(any(String.class));
}
+ @Test
+ public void testMethodArgGenerics() throws IOException {
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;",
+ "import annotation.Anno;",
+ "public class Class<T extends String> {",
+ " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")",
+ " public void method(T arg) {}",
+ "}"));
+ assertThat(mJavac.compile()).isTrue();
+
+ new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+ .visit();
+
+ assertNoErrors();
+ ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+ verify(mStatus, times(1)).greylistEntry(greylist.capture());
+ assertThat(greylist.getValue()).isEqualTo("La/b/Class;->method(Ljava/lang/String;)V");
+ }
+
+ @Test
+ public void testOverrideMethodWithBridge() throws IOException {
+ mJavac.addSource("a.b.Base", Joiner.on('\n').join(
+ "package a.b;",
+ "abstract class Base<T> {",
+ " protected abstract void method(T arg);",
+ "}"));
+
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;",
+ "import annotation.Anno;",
+ "public class Class<T extends String> extends Base<T> {",
+ " @Override",
+ " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")",
+ " public void method(T arg) {}",
+ "}"));
+ assertThat(mJavac.compile()).isTrue();
+
+ new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), ANNOTATION, mStatus)
+ .visit();
+ new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+ .visit();
+
+ assertNoErrors();
+ ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+ // A bridge method is generated for the above, so we expect 2 greylist entries.
+ verify(mStatus, times(2)).greylistEntry(greylist.capture());
+ assertThat(greylist.getAllValues()).containsExactly(
+ "La/b/Class;->method(Ljava/lang/Object;)V",
+ "La/b/Class;->method(Ljava/lang/String;)V");
+ }
+
+ @Test
+ public void testOverridePublicMethodWithBridge() throws IOException {
+ mJavac.addSource("a.b.Base", Joiner.on('\n').join(
+ "package a.b;",
+ "public abstract class Base<T> {",
+ " public void method(T arg) {}",
+ "}"));
+
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;",
+ "import annotation.Anno;",
+ "public class Class<T extends String> extends Base<T> {",
+ " @Override",
+ " @Anno(expectedSignature=\"La/b/Class;->method(Ljava/lang/String;)V\")",
+ " public void method(T arg) {}",
+ "}"));
+ assertThat(mJavac.compile()).isTrue();
+
+ new AnnotationVisitor(mJavac.getCompiledClass("a.b.Base"), ANNOTATION, mStatus)
+ .visit();
+ new AnnotationVisitor(mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus)
+ .visit();
+
+ assertNoErrors();
+ ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+ // A bridge method is generated for the above, so we expect 2 greylist entries.
+ verify(mStatus, times(2)).greylistEntry(greylist.capture());
+ assertThat(greylist.getAllValues()).containsExactly(
+ "La/b/Class;->method(Ljava/lang/Object;)V",
+ "La/b/Class;->method(Ljava/lang/String;)V");
+ }
+
+ @Test
+ public void testBridgeMethodsFromInterface() throws IOException {
+ mJavac.addSource("a.b.Interface", Joiner.on('\n').join(
+ "package a.b;",
+ "public interface Interface {",
+ " public void method(Object arg);",
+ "}"));
+
+ mJavac.addSource("a.b.Base", Joiner.on('\n').join(
+ "package a.b;",
+ "import annotation.Anno;",
+ "class Base {",
+ " @Anno(expectedSignature=\"La/b/Base;->method(Ljava/lang/Object;)V\")",
+ " public void method(Object arg) {}",
+ "}"));
+
+ mJavac.addSource("a.b.Class", Joiner.on('\n').join(
+ "package a.b;",
+ "public class Class extends Base implements Interface {",
+ "}"));
+ assertThat(mJavac.compile()).isTrue();
+
+ new AnnotationVisitor(
+ mJavac.getCompiledClass("a.b.Interface"), ANNOTATION, mStatus).visit();
+ new AnnotationVisitor(
+ mJavac.getCompiledClass("a.b.Base"), ANNOTATION, mStatus).visit();
+ new AnnotationVisitor(
+ mJavac.getCompiledClass("a.b.Class"), ANNOTATION, mStatus).visit();
+
+ assertNoErrors();
+ ArgumentCaptor<String> greylist = ArgumentCaptor.forClass(String.class);
+ // A bridge method is generated for the above, so we expect 2 greylist entries.
+ verify(mStatus, times(2)).greylistEntry(greylist.capture());
+ assertThat(greylist.getAllValues()).containsExactly(
+ "La/b/Class;->method(Ljava/lang/Object;)V",
+ "La/b/Base;->method(Ljava/lang/Object;)V");
+ }
}
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index 0381381bbf..e4bec060f2 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -75,7 +75,9 @@ NO_RETURN static void Usage(const char* fmt, ...) {
UsageError("");
UsageError(" Command \"list\": dump lists of public and private API");
UsageError(" --boot-dex=<filename>: dex file which belongs to boot class path");
- UsageError(" --stub-dex=<filename>: dex/apk file which belongs to SDK API stubs");
+ UsageError(" --stub-classpath=<filenames>: colon-separated list of dex/apk files");
+ UsageError(" which form API stubs of boot class path. Multiple classpaths can");
+ UsageError(" be specified");
UsageError("");
UsageError(" --out-public=<filename>: output file for a list of all public APIs");
UsageError(" --out-private=<filename>: output file for a list of all private APIs");
@@ -121,7 +123,7 @@ class DexClass {
return list;
}
- inline bool IsVisible() const { return HasAccessFlags(kAccPublic); }
+ inline bool IsPublic() const { return HasAccessFlags(kAccPublic); }
inline bool Equals(const DexClass& other) const {
bool equals = GetDescriptor() == other.GetDescriptor();
@@ -178,11 +180,10 @@ class DexMember {
inline bool IsMethod() const { return it_.IsAtMethod(); }
inline bool IsVirtualMethod() const { return it_.IsAtVirtualMethod(); }
+ inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); }
- // Returns true if the member is public/protected and is in a public class.
- inline bool IsVisible() const {
- return GetDeclaringClass().IsVisible() &&
- (HasAccessFlags(kAccPublic) || HasAccessFlags(kAccProtected));
+ inline bool IsPublicOrProtected() const {
+ return HasAccessFlags(kAccPublic) || HasAccessFlags(kAccProtected);
}
// Constructs a string with a unique signature of this class member.
@@ -344,6 +345,24 @@ class HierarchyClass FINAL {
return ForEachResolvableMember_Impl(other, fn) != ResolutionResult::kNotFound;
}
+ // 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;
+ }
+
+ // Recursively iterates over all subclasses of this class and invokes `fn`
+ // on each one. If `fn` returns false for a particular subclass, exploring its
+ // subclasses is skipped.
+ template<typename Fn>
+ void ForEachSubClass(Fn fn) {
+ for (HierarchyClass* subclass : extended_by_) {
+ if (fn(subclass)) {
+ subclass->ForEachSubClass(fn);
+ }
+ }
+ }
+
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
@@ -438,7 +457,7 @@ class HierarchyClass FINAL {
class Hierarchy FINAL {
public:
- explicit Hierarchy(ClassPath& class_path) : class_path_(class_path) {
+ explicit Hierarchy(ClassPath& classpath) : classpath_(classpath) {
BuildClassHierarchy();
}
@@ -454,6 +473,48 @@ class Hierarchy FINAL {
return (klass != nullptr) && klass->ForEachResolvableMember(other, fn);
}
+ // Returns true if `member`, which belongs to this classpath, is visible to
+ // code in child class loaders.
+ bool IsMemberVisible(const DexMember& member) {
+ if (!member.IsPublicOrProtected()) {
+ // Member is private or package-private. Cannot be visible.
+ return false;
+ } else if (member.GetDeclaringClass().IsPublic()) {
+ // Member is public or protected, and class is public. It must be visible.
+ return true;
+ } else if (member.IsConstructor()) {
+ // Member is public or protected constructor and class is not public.
+ // Must be hidden because it cannot be implicitly exposed by a subclass.
+ return false;
+ } else {
+ // Member is public or protected method, but class is not public. Check if
+ // it is exposed through a public subclass.
+ // Example code (`foo` exposed by ClassB):
+ // class ClassA { public void foo() { ... } }
+ // public class ClassB extends ClassA {}
+ HierarchyClass* klass = FindClass(member.GetDeclaringClass().GetDescriptor());
+ CHECK(klass != nullptr);
+ bool visible = false;
+ klass->ForEachSubClass([&visible, &member](HierarchyClass* subclass) {
+ if (subclass->HasMatchingMember(member)) {
+ // There is a member which matches `member` in `subclass`, either
+ // a virtual method overriding `member` or a field overshadowing
+ // `member`. In either case, `member` remains hidden.
+ CHECK(member.IsVirtualMethod() || !member.IsMethod());
+ return false; // do not explore deeper
+ } else if (subclass->GetOneDexClass().IsPublic()) {
+ // `subclass` inherits and exposes `member`.
+ visible = true;
+ return false; // do not explore deeper
+ } else {
+ // `subclass` inherits `member` but does not expose it.
+ return true; // explore deeper
+ }
+ });
+ return visible;
+ }
+ }
+
private:
HierarchyClass* FindClass(const std::string& descriptor) {
auto it = classes_.find(descriptor);
@@ -467,7 +528,7 @@ class Hierarchy FINAL {
void BuildClassHierarchy() {
// Create one HierarchyClass entry in `classes_` per class descriptor
// and add all DexClass objects with the same descriptor to that entry.
- class_path_.ForEachDexClass([this](DexClass& klass) {
+ classpath_.ForEachDexClass([this](DexClass& klass) {
classes_[klass.GetDescriptor()].AddDexClass(klass);
});
@@ -494,7 +555,7 @@ class Hierarchy FINAL {
}
}
- ClassPath& class_path_;
+ ClassPath& classpath_;
std::map<std::string, HierarchyClass> classes_;
};
@@ -547,8 +608,9 @@ class HiddenApi FINAL {
const StringPiece option(argv[i]);
if (option.starts_with("--boot-dex=")) {
boot_dex_paths_.push_back(option.substr(strlen("--boot-dex=")).ToString());
- } else if (option.starts_with("--stub-dex=")) {
- stub_dex_paths_.push_back(option.substr(strlen("--stub-dex=")).ToString());
+ } else if (option.starts_with("--stub-classpath=")) {
+ stub_classpaths_.push_back(android::base::Split(
+ option.substr(strlen("--stub-classpath=")).ToString(), ":"));
} else if (option.starts_with("--out-public=")) {
out_public_path_ = option.substr(strlen("--out-public=")).ToString();
} else if (option.starts_with("--out-private=")) {
@@ -578,10 +640,10 @@ class HiddenApi FINAL {
OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist);
// Open all dex files.
- ClassPath boot_class_path(boot_dex_paths_, /* open_writable */ true);
+ ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ true);
// Set access flags of all members.
- boot_class_path.ForEachDexMember([&api_list](DexMember& boot_member) {
+ boot_classpath.ForEachDexMember([&api_list](DexMember& boot_member) {
auto it = api_list.find(boot_member.GetApiEntry());
if (it == api_list.end()) {
boot_member.SetHidden(HiddenApiAccessFlags::kWhitelist);
@@ -590,7 +652,7 @@ class HiddenApi FINAL {
}
});
- boot_class_path.UpdateDexChecksums();
+ boot_classpath.UpdateDexChecksums();
}
void OpenApiFile(const std::string& path,
@@ -614,7 +676,7 @@ class HiddenApi FINAL {
void ListApi() {
if (boot_dex_paths_.empty()) {
Usage("No boot DEX files specified");
- } else if (stub_dex_paths_.empty()) {
+ } else if (stub_classpaths_.empty()) {
Usage("No stub DEX files specified");
} else if (out_public_path_.empty()) {
Usage("No public API output path specified");
@@ -630,39 +692,42 @@ class HiddenApi FINAL {
std::set<std::string> unresolved;
// Open all dex files.
- ClassPath stub_class_path(stub_dex_paths_, /* open_writable */ false);
- ClassPath boot_class_path(boot_dex_paths_, /* open_writable */ false);
- Hierarchy boot_hierarchy(boot_class_path);
+ ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ false);
+ Hierarchy boot_hierarchy(boot_classpath);
// Mark all boot dex members private.
- boot_class_path.ForEachDexMember([&boot_members](DexMember& boot_member) {
+ boot_classpath.ForEachDexMember([&boot_members](DexMember& boot_member) {
boot_members[boot_member.GetApiEntry()] = false;
});
// Resolve each SDK dex member against the framework and mark it white.
- stub_class_path.ForEachDexMember(
- [&boot_hierarchy, &boot_members, &unresolved](DexMember& stub_member) {
- if (!stub_member.IsVisible()) {
- // Typically fake constructors and inner-class `this` fields.
- return;
- }
- bool resolved = boot_hierarchy.ForEachResolvableMember(
- stub_member,
- [&boot_members](DexMember& boot_member) {
- std::string entry = boot_member.GetApiEntry();
- auto it = boot_members.find(entry);
- CHECK(it != boot_members.end());
- if (it->second) {
- return false; // has been marked before
- } else {
- it->second = true;
- return true; // marked for the first time
- }
- });
- if (!resolved) {
- unresolved.insert(stub_member.GetApiEntry());
- }
- });
+ for (const std::vector<std::string>& stub_classpath_dex : stub_classpaths_) {
+ ClassPath stub_classpath(stub_classpath_dex, /* open_writable */ false);
+ Hierarchy stub_hierarchy(stub_classpath);
+ stub_classpath.ForEachDexMember(
+ [&stub_hierarchy, &boot_hierarchy, &boot_members, &unresolved](DexMember& stub_member) {
+ if (!stub_hierarchy.IsMemberVisible(stub_member)) {
+ // Typically fake constructors and inner-class `this` fields.
+ return;
+ }
+ bool resolved = boot_hierarchy.ForEachResolvableMember(
+ stub_member,
+ [&boot_members](DexMember& boot_member) {
+ std::string entry = boot_member.GetApiEntry();
+ auto it = boot_members.find(entry);
+ CHECK(it != boot_members.end());
+ if (it->second) {
+ return false; // has been marked before
+ } else {
+ it->second = true;
+ return true; // marked for the first time
+ }
+ });
+ if (!resolved) {
+ unresolved.insert(stub_member.GetApiEntry());
+ }
+ });
+ }
// Print errors.
for (const std::string& str : unresolved) {
@@ -685,7 +750,10 @@ class HiddenApi FINAL {
// Paths to DEX files which should be processed.
std::vector<std::string> boot_dex_paths_;
- std::vector<std::string> stub_dex_paths_;
+
+ // Set of public API stub classpaths. Each classpath is formed by a list
+ // of DEX/APK files in the order they appear on the classpath.
+ std::vector<std::vector<std::string>> stub_classpaths_;
// Paths to text files which contain the lists of API members.
std::string light_greylist_path_;
diff --git a/tools/jfuzz/jfuzz.cc b/tools/jfuzz/jfuzz.cc
index 60c62752ef..a97a99ce4b 100644
--- a/tools/jfuzz/jfuzz.cc
+++ b/tools/jfuzz/jfuzz.cc
@@ -1302,7 +1302,7 @@ class JFuzz {
int32_t main(int32_t argc, char** argv) {
// Time-based seed.
struct timeval tp;
- gettimeofday(&tp, NULL);
+ gettimeofday(&tp, nullptr);
// Defaults.
uint32_t seed = (tp.tv_sec * 1000000 + tp.tv_usec);
diff --git a/tools/libcore_gcstress_debug_failures.txt b/tools/libcore_gcstress_debug_failures.txt
index 06f6339d76..942a4e0fc6 100644
--- a/tools/libcore_gcstress_debug_failures.txt
+++ b/tools/libcore_gcstress_debug_failures.txt
@@ -9,13 +9,14 @@
result: EXEC_FAILED,
modes: [device],
names: ["jsr166.CompletableFutureTest#testCompleteOnTimeout_completed",
+ "jsr166.CompletableFutureTest#testDelayedExecutor",
"libcore.libcore.icu.TransliteratorTest#testAll",
"libcore.libcore.icu.RelativeDateTimeFormatterTest#test_bug25821045",
"libcore.libcore.icu.RelativeDateTimeFormatterTest#test_bug25883157",
"libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndTimeout",
- "libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndNoTimeout",
"libcore.java.util.TimeZoneTest#testSetDefaultDeadlock",
"libcore.javax.crypto.CipherBasicsTest#testBasicEncryption",
+ "org.apache.harmony.tests.java.text.MessageFormatTest#test_parseLjava_lang_String",
"org.apache.harmony.tests.java.util.TimerTest#testThrowingTaskKillsTimerThread"]
},
{
diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt
index e049cb3ee9..6840f9ebec 100644
--- a/tools/libcore_gcstress_failures.txt
+++ b/tools/libcore_gcstress_failures.txt
@@ -9,5 +9,39 @@
result: EXEC_FAILED,
modes: [device],
names: ["libcore.javax.crypto.CipherBasicsTest#testGcmEncryption"]
+},
+{
+ description: "Timeouts.",
+ result: EXEC_FAILED,
+ names: ["libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndNoTimeout"]
+},
+{
+ description: "Timeouts.",
+ result: EXEC_FAILED,
+ modes: [host],
+ names: ["libcore.java.lang.ref.ReferenceQueueTest#testRemoveWithDelayedResultAndTimeout",
+ "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest#testGetOutputStream",
+ "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest#testProxyAuthorization"]
+},
+{
+ description: "Timeouts.",
+ result: EXEC_FAILED,
+ modes: [device],
+ names: ["libcore.java.lang.StringTest#testFastPathString_wellFormedUtf8Sequence",
+ "org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_remove",
+ "org.apache.harmony.tests.java.util.TimerTest#testOverdueTaskExecutesImmediately",
+ "org.apache.harmony.tests.java.util.WeakHashMapTest#test_keySet_hasNext",
+ "libcore.java.text.DecimalFormatTest#testCurrencySymbolSpacing",
+ "libcore.java.text.SimpleDateFormatTest#testLocales"]
+},
+{
+ description: "GC crash",
+ result: EXEC_FAILED,
+ bug: 111545159,
+ names: ["org.apache.harmony.tests.java.util.AbstractSequentialListTest#test_addAllILjava_util_Collection",
+ "org.apache.harmony.tests.java.util.HashtableTest#test_putLjava_lang_ObjectLjava_lang_Object",
+ "org.apache.harmony.tests.java.util.VectorTest#test_addAllILjava_util_Collection",
+ "org.apache.harmony.tests.java.util.VectorTest#test_addAllLjava_util_Collection",
+ "org.apache.harmony.tests.java.io.BufferedWriterTest#test_write_LStringII_Exception"]
}
]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index aff009abb6..240d63c6d3 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -156,7 +156,11 @@ fi
# Increase the timeout, as vogar cannot set individual test
# timeout when being asked to run packages, and some tests go above
# the default timeout.
-vogar_args="$vogar_args --timeout 480"
+if $gcstress && $debug && $device_mode; then
+ vogar_args="$vogar_args --timeout 960"
+else
+ vogar_args="$vogar_args --timeout 480"
+fi
# set the toolchain to use.
vogar_args="$vogar_args --toolchain d8 --language CUR"
diff --git a/tools/veridex/flow_analysis.cc b/tools/veridex/flow_analysis.cc
index d4f7e5f91d..f5eb4ea67d 100644
--- a/tools/veridex/flow_analysis.cc
+++ b/tools/veridex/flow_analysis.cc
@@ -17,6 +17,7 @@
#include "flow_analysis.h"
#include "dex/bytecode_utils.h"
+#include "dex/class_accessor-inl.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_instruction-inl.h"
#include "dex/dex_file-inl.h"
@@ -26,6 +27,13 @@
namespace art {
+VeriFlowAnalysis::VeriFlowAnalysis(VeridexResolver* resolver,
+ const ClassAccessor::Method& method)
+ : resolver_(resolver),
+ method_id_(method.GetIndex()),
+ code_item_accessor_(method.GetInstructionsAndData()),
+ dex_registers_(code_item_accessor_.InsnsSizeInCodeUnits()),
+ instruction_infos_(code_item_accessor_.InsnsSizeInCodeUnits()) {}
void VeriFlowAnalysis::SetAsBranchTarget(uint32_t dex_pc) {
if (dex_registers_[dex_pc] == nullptr) {
diff --git a/tools/veridex/flow_analysis.h b/tools/veridex/flow_analysis.h
index fc093600c3..9c86024711 100644
--- a/tools/veridex/flow_analysis.h
+++ b/tools/veridex/flow_analysis.h
@@ -17,6 +17,7 @@
#ifndef ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
#define ART_TOOLS_VERIDEX_FLOW_ANALYSIS_H_
+#include "dex/class_accessor.h"
#include "dex/code_item_accessors.h"
#include "dex/dex_file_reference.h"
#include "dex/method_reference.h"
@@ -108,12 +109,7 @@ struct InstructionInfo {
class VeriFlowAnalysis {
public:
- VeriFlowAnalysis(VeridexResolver* resolver, const ClassDataItemIterator& it)
- : resolver_(resolver),
- method_id_(it.GetMemberIndex()),
- code_item_accessor_(resolver->GetDexFile(), it.GetMethodCodeItem()),
- dex_registers_(code_item_accessor_.InsnsSizeInCodeUnits()),
- instruction_infos_(code_item_accessor_.InsnsSizeInCodeUnits()) {}
+ VeriFlowAnalysis(VeridexResolver* resolver, const ClassAccessor::Method& method);
void Run();
@@ -189,8 +185,8 @@ struct ReflectAccessInfo {
// Collects all reflection uses.
class FlowAnalysisCollector : public VeriFlowAnalysis {
public:
- FlowAnalysisCollector(VeridexResolver* resolver, const ClassDataItemIterator& it)
- : VeriFlowAnalysis(resolver, it) {}
+ FlowAnalysisCollector(VeridexResolver* resolver, const ClassAccessor::Method& method)
+ : VeriFlowAnalysis(resolver, method) {}
const std::vector<ReflectAccessInfo>& GetUses() const {
return uses_;
@@ -208,9 +204,9 @@ class FlowAnalysisCollector : public VeriFlowAnalysis {
class FlowAnalysisSubstitutor : public VeriFlowAnalysis {
public:
FlowAnalysisSubstitutor(VeridexResolver* resolver,
- const ClassDataItemIterator& it,
+ const ClassAccessor::Method& method,
const std::map<MethodReference, std::vector<ReflectAccessInfo>>& accesses)
- : VeriFlowAnalysis(resolver, it), accesses_(accesses) {}
+ : VeriFlowAnalysis(resolver, method), accesses_(accesses) {}
const std::vector<ReflectAccessInfo>& GetUses() const {
return uses_;
diff --git a/tools/veridex/hidden_api_finder.cc b/tools/veridex/hidden_api_finder.cc
index 8c6139f75a..4eba10e764 100644
--- a/tools/veridex/hidden_api_finder.cc
+++ b/tools/veridex/hidden_api_finder.cc
@@ -16,6 +16,7 @@
#include "hidden_api_finder.h"
+#include "dex/class_accessor-inl.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_instruction-inl.h"
#include "dex/dex_file.h"
@@ -62,23 +63,9 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
}
// Note: we collect strings constants only referenced in code items as the string table
// contains other kind of strings (eg types).
- size_t class_def_count = dex_file.NumClassDefs();
- for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- const uint8_t* class_data = dex_file.GetClassData(class_def);
- if (class_data == nullptr) {
- // Empty class.
- continue;
- }
- ClassDataItemIterator it(dex_file, class_data);
- it.SkipAllFields();
- for (; it.HasNextMethod(); it.Next()) {
- const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
- if (code_item == nullptr) {
- continue;
- }
- CodeItemDataAccessor code_item_accessor(dex_file, code_item);
- for (const DexInstructionPcPair& inst : code_item_accessor) {
+ for (ClassAccessor accessor : dex_file.GetClasses()) {
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ for (const DexInstructionPcPair& inst : method.GetInstructions()) {
switch (inst->Opcode()) {
case Instruction::CONST_STRING: {
dex::StringIndex string_index(inst->VRegB_21c());
@@ -103,8 +90,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
// We only keep track of the location for strings, as these will be the
// field/method names the user is interested in.
strings_.insert(name);
- reflection_locations_[name].push_back(
- MethodReference(&dex_file, it.GetMemberIndex()));
+ reflection_locations_[name].push_back(method.GetReference());
}
}
break;
@@ -114,8 +100,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
case Instruction::INVOKE_STATIC:
case Instruction::INVOKE_SUPER:
case Instruction::INVOKE_VIRTUAL: {
- CheckMethod(
- inst->VRegB_35c(), resolver, MethodReference(&dex_file, it.GetMemberIndex()));
+ CheckMethod(inst->VRegB_35c(), resolver, method.GetReference());
break;
}
@@ -124,8 +109,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
case Instruction::INVOKE_STATIC_RANGE:
case Instruction::INVOKE_SUPER_RANGE:
case Instruction::INVOKE_VIRTUAL_RANGE: {
- CheckMethod(
- inst->VRegB_3rc(), resolver, MethodReference(&dex_file, it.GetMemberIndex()));
+ CheckMethod(inst->VRegB_3rc(), resolver, method.GetReference());
break;
}
@@ -136,8 +120,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
case Instruction::IGET_BYTE:
case Instruction::IGET_CHAR:
case Instruction::IGET_SHORT: {
- CheckField(
- inst->VRegC_22c(), resolver, MethodReference(&dex_file, it.GetMemberIndex()));
+ CheckField(inst->VRegC_22c(), resolver, method.GetReference());
break;
}
@@ -148,8 +131,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
case Instruction::IPUT_BYTE:
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
- CheckField(
- inst->VRegC_22c(), resolver, MethodReference(&dex_file, it.GetMemberIndex()));
+ CheckField(inst->VRegC_22c(), resolver, method.GetReference());
break;
}
@@ -160,8 +142,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
case Instruction::SGET_SHORT: {
- CheckField(
- inst->VRegB_21c(), resolver, MethodReference(&dex_file, it.GetMemberIndex()));
+ CheckField(inst->VRegB_21c(), resolver, method.GetReference());
break;
}
@@ -172,8 +153,7 @@ void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) {
case Instruction::SPUT_BYTE:
case Instruction::SPUT_CHAR:
case Instruction::SPUT_SHORT: {
- CheckField(
- inst->VRegB_21c(), resolver, MethodReference(&dex_file, it.GetMemberIndex()));
+ CheckField(inst->VRegB_21c(), resolver, method.GetReference());
break;
}
diff --git a/tools/veridex/precise_hidden_api_finder.cc b/tools/veridex/precise_hidden_api_finder.cc
index 89754c2cdf..445221e8f7 100644
--- a/tools/veridex/precise_hidden_api_finder.cc
+++ b/tools/veridex/precise_hidden_api_finder.cc
@@ -16,6 +16,7 @@
#include "precise_hidden_api_finder.h"
+#include "dex/class_accessor-inl.h"
#include "dex/code_item_accessors-inl.h"
#include "dex/dex_instruction-inl.h"
#include "dex/dex_file.h"
@@ -31,25 +32,13 @@ namespace art {
void PreciseHiddenApiFinder::RunInternal(
const std::vector<std::unique_ptr<VeridexResolver>>& resolvers,
- const std::function<void(VeridexResolver*, const ClassDataItemIterator&)>& action) {
+ const std::function<void(VeridexResolver*, const ClassAccessor::Method&)>& action) {
for (const std::unique_ptr<VeridexResolver>& resolver : resolvers) {
- const DexFile& dex_file = resolver->GetDexFile();
- size_t class_def_count = dex_file.NumClassDefs();
- for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- const uint8_t* class_data = dex_file.GetClassData(class_def);
- if (class_data == nullptr) {
- // Empty class.
- continue;
- }
- ClassDataItemIterator it(dex_file, class_data);
- it.SkipAllFields();
- for (; it.HasNextMethod(); it.Next()) {
- const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
- if (code_item == nullptr) {
- continue;
+ for (ClassAccessor accessor : resolver->GetDexFile().GetClasses()) {
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ if (method.GetCodeItem() != nullptr) {
+ action(resolver.get(), method);
}
- action(resolver.get(), it);
}
}
}
@@ -68,10 +57,10 @@ void PreciseHiddenApiFinder::AddUsesAt(const std::vector<ReflectAccessInfo>& acc
void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolver>>& resolvers) {
// Collect reflection uses.
- RunInternal(resolvers, [this] (VeridexResolver* resolver, const ClassDataItemIterator& it) {
- FlowAnalysisCollector collector(resolver, it);
+ RunInternal(resolvers, [this] (VeridexResolver* resolver, const ClassAccessor::Method& method) {
+ FlowAnalysisCollector collector(resolver, method);
collector.Run();
- AddUsesAt(collector.GetUses(), MethodReference(&resolver->GetDexFile(), it.GetMemberIndex()));
+ AddUsesAt(collector.GetUses(), method.GetReference());
});
// For non-final reflection uses, do a limited fixed point calculation over the code to try
@@ -84,11 +73,11 @@ void PreciseHiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolv
std::map<MethodReference, std::vector<ReflectAccessInfo>> current_uses
= std::move(abstract_uses_);
RunInternal(resolvers,
- [this, current_uses] (VeridexResolver* resolver, const ClassDataItemIterator& it) {
- FlowAnalysisSubstitutor substitutor(resolver, it, current_uses);
+ [this, current_uses] (VeridexResolver* resolver,
+ const ClassAccessor::Method& method) {
+ FlowAnalysisSubstitutor substitutor(resolver, method, current_uses);
substitutor.Run();
- AddUsesAt(substitutor.GetUses(),
- MethodReference(&resolver->GetDexFile(), it.GetMemberIndex()));
+ AddUsesAt(substitutor.GetUses(), method.GetReference());
});
}
}
diff --git a/tools/veridex/precise_hidden_api_finder.h b/tools/veridex/precise_hidden_api_finder.h
index 1c4d0ae84e..8c5126cf1b 100644
--- a/tools/veridex/precise_hidden_api_finder.h
+++ b/tools/veridex/precise_hidden_api_finder.h
@@ -48,7 +48,7 @@ class PreciseHiddenApiFinder {
// Run over all methods of all dex files, and call `action` on each.
void RunInternal(
const std::vector<std::unique_ptr<VeridexResolver>>& resolvers,
- const std::function<void(VeridexResolver*, const ClassDataItemIterator&)>& action);
+ const std::function<void(VeridexResolver*, const ClassAccessor::Method&)>& action);
// Add uses found in method `ref`.
void AddUsesAt(const std::vector<ReflectAccessInfo>& accesses, MethodReference ref);
diff --git a/tools/veridex/resolver.cc b/tools/veridex/resolver.cc
index 9113039b04..56729fffd0 100644
--- a/tools/veridex/resolver.cc
+++ b/tools/veridex/resolver.cc
@@ -16,6 +16,7 @@
#include "resolver.h"
+#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/primitive.h"
#include "hidden_api.h"
@@ -24,34 +25,22 @@
namespace art {
void VeridexResolver::Run() {
- size_t class_def_count = dex_file_.NumClassDefs();
- for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) {
- const DexFile::ClassDef& class_def = dex_file_.GetClassDef(class_def_index);
- std::string name(dex_file_.StringByTypeIdx(class_def.class_idx_));
+ for (ClassAccessor accessor : dex_file_.GetClasses()) {
+ std::string name(accessor.GetDescriptor());
auto existing = type_map_.find(name);
+ const uint32_t type_idx = accessor.GetClassIdx().index_;
if (existing != type_map_.end()) {
// Class already exists, cache it and move on.
- type_infos_[class_def.class_idx_.index_] = *existing->second;
+ type_infos_[type_idx] = *existing->second;
continue;
}
- type_infos_[class_def.class_idx_.index_] = VeriClass(Primitive::Type::kPrimNot, 0, &class_def);
- type_map_[name] = &(type_infos_[class_def.class_idx_.index_]);
-
- const uint8_t* class_data = dex_file_.GetClassData(class_def);
- if (class_data == nullptr) {
- // Empty class.
- continue;
- }
-
- ClassDataItemIterator it(dex_file_, class_data);
- for (; it.HasNextStaticField(); it.Next()) {
- field_infos_[it.GetMemberIndex()] = it.DataPointer();
+ type_infos_[type_idx] = VeriClass(Primitive::Type::kPrimNot, 0, &accessor.GetClassDef());
+ type_map_[name] = &type_infos_[type_idx];
+ for (const ClassAccessor::Field& field : accessor.GetFields()) {
+ field_infos_[field.GetIndex()] = field.GetDataPointer();
}
- for (; it.HasNextInstanceField(); it.Next()) {
- field_infos_[it.GetMemberIndex()] = it.DataPointer();
- }
- for (; it.HasNextMethod(); it.Next()) {
- method_infos_[it.GetMemberIndex()] = it.DataPointer();
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ method_infos_[method.GetIndex()] = method.GetDataPointer();
}
}
}
@@ -148,18 +137,14 @@ VeriMethod VeridexResolver::LookupMethodIn(const VeriClass& kls,
// Look at methods declared in `kls`.
const DexFile& other_dex_file = resolver->dex_file_;
- const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef());
- if (class_data != nullptr) {
- ClassDataItemIterator it(other_dex_file, class_data);
- it.SkipAllFields();
- for (; it.HasNextMethod(); it.Next()) {
- const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(it.GetMemberIndex());
- if (HasSameNameAndSignature(other_dex_file,
- other_method_id,
- method_name,
- method_signature)) {
- return it.DataPointer();
- }
+ ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
+ for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
+ const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(method.GetIndex());
+ if (HasSameNameAndSignature(other_dex_file,
+ other_method_id,
+ method_name,
+ method_signature)) {
+ return method.GetDataPointer();
}
}
@@ -207,17 +192,14 @@ VeriField VeridexResolver::LookupFieldIn(const VeriClass& kls,
// Look at fields declared in `kls`.
const DexFile& other_dex_file = resolver->dex_file_;
- const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef());
- if (class_data != nullptr) {
- ClassDataItemIterator it(other_dex_file, class_data);
- for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) {
- const DexFile::FieldId& other_field_id = other_dex_file.GetFieldId(it.GetMemberIndex());
- if (HasSameNameAndType(other_dex_file,
- other_field_id,
- field_name,
- field_type)) {
- return it.DataPointer();
- }
+ ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
+ for (const ClassAccessor::Field& field : other_dex_accessor.GetFields()) {
+ const DexFile::FieldId& other_field_id = other_dex_file.GetFieldId(field.GetIndex());
+ if (HasSameNameAndType(other_dex_file,
+ other_field_id,
+ field_name,
+ field_type)) {
+ return field.GetDataPointer();
}
}
@@ -260,18 +242,13 @@ VeriMethod VeridexResolver::LookupDeclaredMethodIn(const VeriClass& kls,
}
VeridexResolver* resolver = GetResolverOf(kls);
const DexFile& other_dex_file = resolver->dex_file_;
- const uint8_t* class_data = other_dex_file.GetClassData(*kls.GetClassDef());
- if (class_data != nullptr) {
- ClassDataItemIterator it(other_dex_file, class_data);
- it.SkipAllFields();
- for (; it.HasNextMethod(); it.Next()) {
- const DexFile::MethodId& other_method_id = other_dex_file.GetMethodId(it.GetMemberIndex());
- if (HasSameNameAndSignature(other_dex_file,
- other_method_id,
- method_name,
- type)) {
- return it.DataPointer();
- }
+ ClassAccessor other_dex_accessor(other_dex_file, *kls.GetClassDef());
+ for (const ClassAccessor::Method& method : other_dex_accessor.GetMethods()) {
+ if (HasSameNameAndSignature(other_dex_file,
+ other_dex_file.GetMethodId(method.GetIndex()),
+ method_name,
+ type)) {
+ return method.GetDataPointer();
}
}
return nullptr;