Amazing discovery of the day: JNI on Android lets you access object fields that you're not supposed to, according to Java rules.
Is this capability to bypass access restrictions documented anywhere? Is this an official JNI behavior or specific to the Android flavor of JNI? Is this an undefined behavior? Will the OOP police come for me any moment now?
I understand that relying on unpublished object fields is inherently dangerous and may break anytime; that's not the question here.
UPDATE: looks like applications that target API28 no longer have this capability.
The problem has been described and even addressed in an article, or rather proposal published back in 2006.
Note that Javs defines SecurityManager class, but it considers all JNI calls as security breach and thus your question is a non-issue from their standpoint, like asking "why can I get elevation to Administrator when I only install some driver/service?".
But on Android, things are even more explicit. The official documentation describes this class with the following preface:
Legacy security code; do not use.
Security managers do not provide a secure environment for executing untrusted code. Untrusted code cannot be safely isolated within the Dalvik VM.
(the emphasis is theirs)
If you are looking for stronger words that guarantee that access to native fields and methods from JNI will not go away in a next version of Android, good luck to you.
On the other hand, the chances are higher that some future version of Android will change the names or signatures of some private fields and methods. Moreover, they can change the implementation such that the filed remains, but must be used differently.
Finally note, that all these considerations apply not only to private or package private methods, but also to public methods and fields that did not make it into the official documentation!
Amazing discovery of the day: JNI on Android lets you access object fields that you're not supposed to, according to Java rules.
The abbreviation JNI does not appear anywhere in the question and answers that you linked to, except as a dynamically-generated link to this very question.
Is this documented anywhere?
Any decent book on Java development should cover public, private, etc.
Is this an official JNI behavior or Android-specific?
Neither.
What is Android-specific is compile-time steps to make it difficult for you to add code in some android, java, and javax packages.
Is this an undefined behavior?
That depends on what underlying noun or concept you are tying to tying to the pronoun "this".
If "this" is "accessing private, etc. stuff", then the behavior is not undefined.
If "this" is "accessing something specific private, etc. in the Android framework", that is undefined. There are many, many versions of Android around, and many, many versions of framework classes. Their internal implementations are not identical. Anything not exposed via the Android SDK is eligible for change by Google, device manufacturers, ROM mod maintainers, etc.
Related
In the app that I'm working on I'm trying to get the Album artist from a song file. I made the query with the cursor and extract the album_artist column (https://stackoverflow.com/a/59631970), but the constant with this String (MediaStore.Audio.AudioColumns.ALBUM_ARTIST) prevent my app from compiling causing a Unresolved reference exception.
The constant has a #hide in its JavaDoc which seems to "hide" the field from outside (couldn't find a legit source to back me up here, I might be very wrong).
MediaStore source-code
What is bugging my mind is that the constant exists in the SDK, the column exists (passing the String manually works) and the constant is in the code, so why I cannot use it? If there is a better way what is it? There is no indication in the code and MediaStore.Audio.Albums.ARTIST don't give me the data that I want (gives me the "artist" not the "album artist").
Does someone know what is the proper way to get this data?
(For now I'm leaving the hard-coded String)
One solution is the answer
Which might not reliable do what you want, to guarantee reading of album_artist tag, you must read the tag manually through mediaMetadataRetriever.
You're trying to access a non-sdk interface, those are all methods, constants, classes, etc, that are not referenced in the android documentation.
Before android pie (api 28), you could attempt to use and reference these methods trough reflection, but since then google has blacklisted all usage of non-sdk interfaces. The only exception is when using non-sdk interfaces available at an specific api level, but your app must not support any bellow api levels.
The reason for such change is that non-sdk interfaces are parts of the android ecosystem that must be available at AOSP for some internal reason but are not final or available to the public. Google does not guarantee that any non-sdk interfaces wont change behavior or be deleted, breaking your app. Since developers insisted on using such interfaces in production apps, they decided to rigorously enforce the restriction.
The #hide annotation in javadoc excludes the code from the compiled javaDoc. So, when google builds its documentation, the constant not being in the android documentation is the intended behavior.
You can refer to this question
question and the documentation
ps: The constant you want to access will become part of the android sdk after android R
I am implementing an Android ODM system. I would like to create a VirtualDisplay constructed around an ImageReader so that the process providing the virtual display will receive the series of frames coming out of SurfaceFlinger as HardwareBuffer instances.
The intention is to fetch out the Linux dmabuf handle to each received HardwareBuffer by using AHardwareBuffer_fromHardwareBuffer() to get the corresponding native object, then convert it to an EGLImage with eglCreateNativeClientBufferANDROID() and then finally use eglExportDMABUFImageMESA() to obtain the dmabuf filedescriptor.
The critical piece of API -- AHardwareBuffer_fromHardwareBuffer() -- lives in the native library called "libandroid". Google documentation (see https://source.android.com/devices/architecture/images/vndk_design_android_o.pdf) explicitly indicates that vendor programs are prohibited from using API in libandroid.
This seems strange, because libandroid is already exposed in the application NDK. I think this means that backward portability in all future Android releases is therefore already demanded of libandroid.
Is there any existing way that I can make my vendor program link against this API? If not, could AHardwareBuffer_fromHardwareBuffer() be migrated out to the VNDK in a similar way as some of the other native C++ API's related to AHardwareBuffer have been?
Updated:
It's a pre-installed service that needs (in addition to doing these VirtualDisplay and ImageReader mechanics) to do some interaction with a custom HAL (so: not anything that implements one of the standard Google HIDL interfaces) that my customer is implementing.
I think that relegates us to needing to pre-install into the /vendor partition, right? I don't know whether this technically speaking makes me a "VNDK process", but the restriction against linking against libandroid kicks in anytime that I put "vendor: true" into the Blueprint file.
This pre-installed service sits in the AOSP tree because I'd like to sign it with the platform key so that the service can set its android:persistent property in AndroidManifest.xml to avoid it being subject to arbitrary shutdown from ActivityManager.
Other pre-installed applications will go badly if this VirtualDisplay doesn't end get instantiated. I'm uncertain what this means for GSI. Maybe you're likely to say that, with a GSI image installed for testing, none of those other preinstalled apps are present either so there's no problem.
Is this process a regular application (APK that provides Activities, Services, etc.) that just happens to be pre-installed on the device? I'd imagine it is if you're using VirtualDisplay and ImageReader. If so, there should be no problem using libandroid.
The restriction on libandroid is specifically for VNDK processes, i.e. lower level parts of the system. The restriction is there because several things in libandroid depend on the Android Framework, ART runtime, etc. as well as unversioned and non-fixed internal interfaces to them. So the usual versioning of VNDK-available libraries, where literally vndk binaries from old versions of the OS must work on newer versions of the OS, doesn't work for libandroid because of those dependencies on non-stable internal interfaces.
But if you're writing something that sits above the framework and is only using public APIs, then it's not a VNDK process and those restrictions don't apply.
(Note: I work on Android and have been involved in AHardwareBuffer APIs. But I'm not a VNDK expert nor an expert on the rules around vendor processes and vendor-preinstalled applications. So take this as reflecting my own personal understanding, and not an official statement from the Android team: if there's official documentation that contradicts what I've said, it's probably right and I'm wrong.)
I've been working on a writing a game for Android. Until now I've been using Java instead of the NDK, but I've decided to port my code to C++ (for performance, memory management and industry standards reasons).
Porting my application shouldn't be a problem (I've written my fair share of C++ applications), but I've been using RoboGuice as a dependency injection framework because otherwise my object graph would become too complex rather quickly.
I've been looking around, but I haven't found any resources about using a dependency injection framework in combination with the Android NDK.
Can someone tell me if there any such franeworks available. If so, which one would you recommend?
If you have a C++11 compiler for Android you could use several frameworks (I wrote Infectorpp) but there are others available. You should note that DI is quite limited in C++ due to the lack of reflection so you should make some compromises as not everything you did in RoboGuice would still be possible.
By doing a quick search seems that C++11 is possible on Android. I don't have an Android device and still not needed to emulate it, but if you have any feedback it will be wellcome (private message here or support ticket on google code is enough), the library is headers only so no special build stuff is required for it, apart enabling c++11 on your compiler wich is just one extra option by command line. If that will works good on Android then it will be definitely good also for PC. (Do not misunderstand please, I'm using it heavily, but seems very few people is interested in DI in C++ and so I get very little feedback)
There was also a nice framework cpp-resolver: a little awkard to use because you explicitly register factory functions for injecting ALL parameters, but very scalable, especially for server applications.. (decouple object lifetime management and works with plain old C++).
The most complete framework is probably wallaroo
If you search something really easy to use Infectorpp is a good choice
If you need control over lifetime (mostly servers): Cpp-resolver is perfect
If you need exotic features and configuration files: wallaroo
As side note, run-time configuration is possible also with frameworks that do not explicitly support it:
You just need a Factory that istantiate a different type based on a configuration file you could read through a class that you add as dependency to factories (Probably you don't need to know that since you were already using DI frameworks, but still good to know for occasional readers)
Even a private member/function of my class can be accessed by reflection by using setAccessible(true). Is there a way to prevent this kind of access from outside code?
I read something, here on stack-overflow, that I can use SecurityManager for prevention of reflection in applets(not sure how it works, though), but is there a similar mechanism for Android as well? Maybe an annotation or clever-programming?
Taking a step back, what you're observing is a difference in security philosophy, between the Java execution model as originally embodied in JVMs at Sun and the execution model of Android.
The original Java VM design was intended for a system wherein multiple, mutually-suspicious applications (or "applets" in the Java parlance) would simultaneously inhabit a single address space, running in a single VM. Because the designers didn't want one app to be able to mess with another, they went through great pains to define an intra-VM security model that would disallow things such as one object touching the private fields of another object of a different class.
That said, the Java library ended up having various "escape hatches" out of the security model. One of those is setAccessible() on reflection objects, as you note.
Android's model is different: Android uses processes as the security boundary and unit of application isolation, instead of trying to insinuate it into the process as was done with traditional JVMs. This renders moot the entirety of the Java security model, except in that it helps an application "save it from itself." That is, it's good design to not have an object poke into another object's private parts, and the default Java security model provides just that.
Leaving aside the question of people modifying your code, with Android, as an application author, you control all the code that ends up running inside the process of your app. If you choose to include code that calls setAccessible() that's your business. You might be shooting yourself in the foot, but you certainly won't be shooting any other apps' feet, since the Android security model, running as it as at the layer of processes, inherently doesn't let that happen. Likewise, using native code will totally break you out of the Java object model, which allows for the possibility of things going totally higgledy-piggledy in the process but also allows you to express some things in a more productive manner than you could in Java. It's a trade-off, but it's a per-application-developer tradeoff and not one that particularly impacts anything else that's happening on your phone / device.
I know this doesn't directly answer your question, but I hope it provided some useful context.
Is there a way to prevent this kind of access from outside code?
Not really.
is there a similar mechanism for Android as well?
Even if there is (and I am not aware that such a thing exists), anyone can remove it, by decompiling your code (assuming they do not have your source already), getting rid of the protection, and recompiling the code.
Bear in mind that ProGuard, when used properly, will obfuscate your private classes and methods for your production APK builds. That, plus a lack of documentation, will make it tedious for anyone to gain access to those private classes and methods.
I don't believe that you can ever really 100% protect from users using reflection on your project with malicious intent. You can make it more difficult for users to do it by doing things like obfuscating your code, but it is still possible to reflect on the obfuscated code.
I don't believe SecurityManager can be used for the purpose that you are suggesting, though I could be wrong.
Effective Java (Joshua Bloch) Item 17 says :
"Design and Document or inheritance or else prohibit it"
However, just a cursory glance through the Android APIs reveals that most of the API classes are non-final; which is OK if they are also documented for inheritance (View of Activity, for example). But there are also several non-final classes, but the documentation makes no mention about the inheritability of these classes. Just some arbitrary examples to illustrate my point:
The classes representing the System Services (WifiManager, NotificationManager ...)
Utility classes like UriMatcher.
Some hardware-specific classes like Camera.
Openness and extensibility being the philosophy of Android, is the convention reversed here? Meaning, could one assume that all of the Android API classes are designed to be inherited (whether explicitly documented or otherwise); unless declared final?
Just my €0,02: Clean OO design by the book is one thing, making things work for all possible use cases in practice is another. The principles of clean OO design sometimes are somewhat of academic nature. - And maybe a little bit of black and white.
Think for instance about who uses the Android API provided by google: It's not only app developers but also device manufacturers who need to specialize general APIs for their devices.
So, for me, SW design is neither black nor white in most cases; the shades of grey are important.
And finally: In practice I have seldom (read: never) seen problems caused by "carelessly" omitted final keywords (on classes), while unreflected overuse of final (often caused by thoughts like "my code is sooo [great | ugly], no one will actually ever want to modify it through inheritance") can be quite a pain.
"I know that I know nothing" seems to fit here: It is presumptuous to claim that one knows all the crazy, ingenious, creative, smart,... ideas of others for how one's code may be used in the future beforehand.
The Android developers went to great lengths to ensure that extensibility, while not recommended in many cases, is possible. The motivation behind this appears to be related to testing environments.
For instance, it would be much more difficult to create a faux WifiManager for the purposes of creating unit tests if it were finalized. Without the finalization, it is trivial to subclass the WifiManager (e.g. to mimic "unexpected" wifi disconnection during operation) and return an instance of this subclass from a customized testing Context.
So while you will probably never find a reason to implement a subclass of the these classes in an application that you ship to the end users, the flexibility is there to allow you to extend them if it is necessary for one reason or another.
In the case of utility classes, the answer is simply that the utility of the class is not diminished by allowing the developer to subclass; in many cases, a developer can achieve more understandable code reuse by inheritance than by aggregation and delegation.