Subclassing com.android.okhttp.AndroidShimResponseCache in application - android

I want to subclass ResponseCache and use a subclass of com.android.okhttp.AndroidShimResponseCache as an internal delegate.
In particular I want to add a small pre-caching method to the class, similar to AndroidShimResponseCache.put, but with my own files in the Response to be cached.
Then I would make my class (that inherits from ResponseCache) the system default.
How can I access AndroidShimResponseCache in my code to subclass it in my application?
I'm not able to get it from any repo or library on my device.

Related

Android/Java Standard Package names are they protected

I need to make a reference to a builtin Android Java Class in NDK c++ code.
You can do it by
cls_tm = (*env)->FindClass(env, "javax/crypto/Cipher");
I am worried someone can tamper with apk, extract the java code then create their own class with the package name javax.crypto.Cipher, and read all the sensitive data I am passing to it. I am new to Java and Android so I wanted to know if it is possible to create your own package with same name as built in packages like javax.crypto.Cipher?
It is possible to create classes with the same name. However, they do not take the place of existing classes.
Every class is loaded by a class loader. Class loaders form a hierarchy, with the "bootstrap" class loader at the very top. The class loader that loads your app's classes is created by the Android app framework; it is a child of the "system" class loader, which is a child of the bootstrap loader.
When your app references a class, it asks its class loader to find it by name. Each loader will either return a class that it defined, or ask its parent to find it. (The default behavior is to ask the parent first, but an individual loader can override this.)
javax.crypto.Cipher is part of core.jar, which is loaded by the bootstrap class loader. So unless your application's class loader decides to replace Cipher with its own version, you will get the system version.
(The JNI FindClass call is actually a bit strange. Depending on where you are when you call it, it can actually end up in the system class loader rather than your app's loader. See this section in JNI Tips for an explanation.)
Suppose you really did want to replace Cipher. You can provide your own version, and your app code will happily use it. However, when you try to pass it to some other code in core.jar, your app will fail. This is because classes loaded in the VM aren't unique by name, but rather by the combination of name and class loader. So you can't pass a Cipher+MyAppLoader into something that expects a Cipher+bootstrap.
In any event, if somebody modified your APK, they would have to re-sign it; since they don't have your private key, it wouldn't look like an app that came from you.
If somebody modified a device and replaced the system Cipher with their own version, they can do whatever they want.

Is it possible to override a method from an existing class using Dexmaker?

Is it possible to change at runtime the behaviour of a method from a class already loaded using Dexmaker, by proxing or generating code?
UPDATE
Just a remark: I want to add a method/modify existing one from my own application, not from the android framework.
No. It is not possible.
You could create a new class that extends the original, or possibly even make a copy of the class, with a new name and a tweaked implementation. But you can't replace an existing class.
Your best bet is probably to extract out the code that you might want to modify into a separate class, and then pass in an instance of that class to whatever uses it. And then, if you need to create a new implementation, you can subclass it and pass in the subclass instead.

ClassLoader to replace a pre-loaded class?

General question:
Is it possible to use a ClassLoader to replace a pre-loaded (by the system, e.g. found in Android's %android%/frameworks/base/preloaded-classes file) class?
Specific:
I am attempting to use the DexClassLoader to replace a class found in android.net.* before creating a WebView in my application. I can get a Class object, but getMethods() for example gives me an array I'd expect in the unmodified/original class implementation. Is this due to the preloaded-classes system?
Basic setup & pseudo code:
Modify android.net.* class, adding a few test methods/etc.
Compile and end up with classes.dex
jar cf mytest.jar classes.dex
Include mytest.jar in APK assets
Create DexClassLoader and get Class via loadClass()
getMethods() on Class object returns an array I'd expect to see without modifications present in #1
I can provide more details on the setup I'm using and code if needed.
No you can not. WebView is part of the boot class path, and thus the base class loader. There is nothing you can do to make it use classes in another class loader. In fact, it has already been loaded and linked to the classes it uses before your app is even launched (as part of the zygote process pre-initialization).

Can I store a reference of an AssetManager in a utility class?

I want to create a utility class that loads images contained in the assets/ file structure. It would be tiresome to require all calls to it, or any other utility class calling it, to pass along the Context all the way from the UI.
Would it be possible to just pass it down once, and store it (as long as the utility class is static or a singleton)? Or would that have devastating consequences memory wise?
Also, so no one asks, I'm using the assets/ folder instead of res/ because I want sub-folders, and to access images by name dynamically, which I can't do using resources to my knowledge. For example, I want my sprite object to load all images in the specific sprite's folder, rather than hard coding R.drawable.sprite1front, R.drawable.sprite1leftside, etc.
*edit - Copying the AssetManager would also be fine, if that can be done.
You can use a singleton or a static class for your utility class, but you should initialize it with a reference to an Application object, not an Activity. (Keeping a reference to an Activity is a good way to leak memory.) The best way might be to subclass Application and use that as your utility class. You'll have to declare your Application class in the manifest.

Android: How to best pass data to a view?

I have a view that displays all the levels of my game. These levels are read by the activity and then passed into the view. I could read them from the view, but it's not really its responsibility, and I'm a fan of separation of concerns.
Right now, I'm calling a setter for this:
((GameView) findViewById(R.id.game)).setLevels(loadLevels());
However, I don't like the fact that the view will be dysfunctional if I forget to call the setter. Is there a better way to pass the levels in?
It is also a bit a matter of preference. Theoretically it's perfectly fine to pass the levels as you're doing. Alternatively, if you need more than just set the levels, but provide further functionalities (i.e. also saving of levels) I normally use a separate class responsible for handling such things (i.e. a Repository, some "Manager" class etc...). This class is then passed into the View on the constructor preferably s.t. one is forced to provide it. Of course, in order to separate things, I use interfaces rather than specific implementations s.t. it may then look as follows:
public class MyView {
public MyView(ILevelLoader levelLoader){
this.levelLoader = levelLoader;
}
...
}
Often, this may not work, because the view is something instantiated by the framework directly rather than by the application. In such a situation you're forced to do it through an appropriate setter. It is some sort of MVC/MVP pattern.
Just for your interest, you might also want to take a look at IoC containers and dependency injection. Guice provided by Google is a nice framework I've already used on Android.
I hope I didn't miss the point, but here goes:
Generally you have either a function setting something (like the text for a textview), or an attribute you set in the xml.
Take a look over at this answer I got on a question: How to layout a 'grid' of images in the center of the screen
There are some things the custom view needs, but lets take an example: 'numColumns'.
you can set it using setNumColumns (that would be the equivalent of your loadLevels() ? )
you can ignore it, it'll revert to default.
you can set it as an attribute lik so: app:numColumns="3"
You can try to use the attribute or the default in the class to accomplish this.
Make your view an abstract class with an abstract method getLevels()? This way, when you instantiate the class if you forget to pass the levels in your code won't compile.
Whether or not this is better is a matter of taste I guess :)

Categories

Resources