Port the "abstract methods are not implementations" fix to art.

Bug: https://code.google.com/p/android/issues/detail?id=42991
Change-Id: I08e46361a9d7275bc870ee1ec38c40ae22ddf08a
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 0e26791..56c37fd 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -3300,7 +3300,7 @@
           mirror::AbstractMethod* vtable_method = vtable->Get(k);
           vtable_mh.ChangeMethod(vtable_method);
           if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
-            if (!vtable_method->IsPublic()) {
+            if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
               self->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
                                        "Implementation not public: %s",
                                        PrettyMethod(vtable_method).c_str());
diff --git a/test/301-abstract-protected/expected.txt b/test/301-abstract-protected/expected.txt
new file mode 100644
index 0000000..b0aad4d
--- /dev/null
+++ b/test/301-abstract-protected/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/301-abstract-protected/info.txt b/test/301-abstract-protected/info.txt
new file mode 100644
index 0000000..0751eff
--- /dev/null
+++ b/test/301-abstract-protected/info.txt
@@ -0,0 +1,3 @@
+Tests a dalvik bug where we'd treat an abstract method as an implementation
+of an interface method; the RI only cares about the visibility of the actual
+implementation in non-abstract subclasses.
diff --git a/test/301-abstract-protected/src/Main.java b/test/301-abstract-protected/src/Main.java
new file mode 100644
index 0000000..9b19a9d
--- /dev/null
+++ b/test/301-abstract-protected/src/Main.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+public class Main {
+  public static void main(String args[]) throws Exception {
+    System.err.println(new C().m());
+  }
+}
+
+// An arbitrary interface.
+interface I { public String m(); }
+
+// This is I-like, but doesn't actually claim to implement I.
+abstract class Abstract { protected abstract String m(); }
+
+// This claims to implement I, but the inherited m isn't sufficiently visible.
+abstract class AbstractI extends Abstract implements I { }
+
+// This has a concrete m that's sufficiently visible, so all should be good.
+class C extends AbstractI { public String m() { return "passed"; }; }