Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android method with default (package) visibility overriding (shouldn't work, but does - why?)

I've been playing around with SVG support in Android and came up with this library which claims that it supports SVG just as it they were native.

Since I took great pains in discovering that this is not really possible, I went to see how this dude actually managed it. So I came upon his Resources derivative in which he declares a method (loadDrawable) that has default visibility in base Resources class.

The funny thing is, normally lint would just report that you can't write this method since it would hide base method, but in this particular case (note the absense of @Override directive) this method gets to be called as if it were written in the base class. All the methods invoking this method will invoke the override instead of original method. For me coming from classic compilers such as C++ or Pascal, this is totally beyond comprehension.

Based on this, I managed to get my SVG support working completely with one single use of reflection and am super-happy about this, but:

Why does this work?

like image 363
velis Avatar asked Apr 11 '14 07:04

velis


1 Answers

It looks like there is a bug in the Dalvik interpreter which allows package-private methods to be overridden. Apparently, Google recognized this issue (in Jelly Bean?), as Dalvik reports a warning that it is incorrectly overriding a package-private method in this case, and ART reports it as an error and fails to compile it. The correct behaviour would of course be to allow it but not allow overriding package-private methods from other packages, but it looks like Google want to avoid breaking existing applications that depend on this behaviour.

UPDATE: This is now officially confirmed in the ART documentation update on June 16, although it states that ART issues a warning instead of a critical error as velis reported in the comments on the question:

Dalvik incorrectly allowed subclasses to override package-private methods. ART issues a warning in such cases:

Before Android 4.1, method void com.foo.Bar.quux()
would have incorrectly overridden the package-private method in
com.quux.Quux

If you intend to override a class's method in a different package, declare the method as public or protected.

like image 179
corsair992 Avatar answered Nov 18 '22 14:11

corsair992