android.os.Handler class has a hide constructor --> void Handler(boolean async),
I just want to call this method by reflection,but in vain...
here is my code:
Class clazz = Class.forName("android.os.Handler");
Constructor construct = clazz.getConstructor(boolean.class);
//Constructor construct = clazz.getDeclaredConstructor(boolean.class);
construct.setAccessible(true);
boolean[] ailments = new boolean[]{true};
Handler handler = (Handler) construct.newInstance(ailments);
the error message is:
java.lang.NoSuchMethodException: android.os.Handler.<init>(boolean)
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getConstructor(Class.java:1825)....
I try to iterate the clazz.getConstructors() returns Constructor array, and log their ParamsType, just find Looper,Callback ...
why it can't log out 'boolean'?
public More ...Handler(boolean async) {
this(null, async);
}
I have resolved this problem by importing the framework.jar instead of android.jar in android/sdk/platforms/android+versioncode/
adk had cut down the #hide api and internal classes to generate the android.jar,we can't use these resources unless we use framework.jar for developing.
see this project,it provided complete classes which included #hide api and internal classes.
android-hidden-api
I think you just need to call construct.newInstance(true) instead of passing the boolean as an array
Related
I am coming from Java and C++ background. However, I am doing a C# application at the moment and one thing made me confused.
In Java when I import a package, it means I can access the classes that are placed in that package. For example, here I imported the ArrayList class from package java.util.
import java.util.ArrayList;
class ArrayListUtilization {
public static void main(String[] args) {
ArrayList<Integer> myList = new ArrayList<>(3);
myList.add(3);
myList.add(2);
myList.add(1);
System.out.println(myList);
}
}
Recently I had a problem in my c-sharp app, that I asked here. The funny part in my point of view is, when I added the following snippet of code:
var accountDbContext = services.GetRequiredService<AccountDbContext>();
accountDbContext.Database.EnsureCreated();
var accountDbCreator = accountDbContext.GetService<IRelationalDatabaseCreator>();
accountDbCreator.CreateTables();
I saw an error as following:
Error CS1929 'AccountDbContext' does not contain a definition for
'GetService' and the best extension method overload
'ServiceProviderServiceExtensions.GetService(IServiceProvider)'
requires a receiver of type 'IServiceProvider'
and from the error text, I understood accountDbContext object does not have GetService function. But when I press on show potential fixes, then it suggests me to add a using statement.
And it was the real fix. However, my question is what is the effect of this using statement on my object? The object is an instantiation of its class. How can adding a using statement effect on my object and add a function to it?
Note that what you are actually calling an extension method here:
accountDbContext.GetService<IRelationalDatabaseCreator>();
accountDbContext does not have a method called GetService. GetService is declared in AccessorExtensions, and the above line is just syntactic sugar for:
AccessorExtensions.GetService<IRelationalDatabaseCreator>(accountDbContext);
Now it should make sense that you need to add a using directive for the class in which the extension method is declared, in order to access the extension method.
I'm using the Xposed module to analyze an android app, and I'm trying to hook a constructor that's declared as private, but it's unable to find the class. Is it because the constructor is private or is there another issue? The constructor is: private CalendarContractCompat() {}. My hook code is:
findAndHookConstructor("com.android.calendar.CalendarContractCompat", lpparam.classLoader, new XC_MethodHook() {
Thanks in advance!
According to xposed bridge source (https://github.com/rovo89/XposedBridge/blob/art/app/src/main/java/de/robv/android/xposed/XposedHelpers.java), findAndHookConstructor calls getDeclaredConstructor and set its result to be accessible. That means the function should work on any constructor, public or not.
Can you hook a public method of the same class?
I am attempting to make a custom implementation of Android's StackView by extending AdapterViewAnimator myself. There are several methods contained in AdapterViewAnimator which would prove useful to my subclass, and so I put my subclass in the same package android.widget hoping to gain access to them since they are package-level methods:
void configureViewAnimator(int numVisibleViews, int activeOffset) {
if (activeOffset > numVisibleViews - 1) {
// Throw an exception here.
}
mMaxNumActiveViews = numVisibleViews;
mActiveOffset = activeOffset;
mPreviousViews.clear();
mViewsMap.clear();
removeAllViewsInLayout();
mCurrentWindowStart = 0;
mCurrentWindowEnd = -1;
}
Note that this method is a package level method, which is why my subclass needs to be in android.widget as well. Even so, the compiler (Java 7) tells me that the method does not exist, and so I cannot call the method on my superclass in my class:
package android.widget;
public class Foo extends AdapterViewAnimator {
public void init(){
super.configureViewAnimator(3,1); // Method does not exist.
}
}
Am I missing something here? Why can't my subclass call the superclass package-level method?
You can refer to https://groups.google.com/forum/#!msg/android-developers/poC2Xyh-G4w/zKLBPNTryYMJ
"Android.jar now contains only the public APIs. If you compile against this jar, you are guaranteed your app will run against future versions of Android. As part of the process that removes private APIs from android.jar, the code is stubbed out, because it's never executed so there's no reason to make the SDK much bigger because of it."
This explain why the method configureViewAnimator is not found as you are compiling against the android.jar, which include only public API(configureViewAnimator is a package private method)
How can I read the bytecode instructions from the body of a lambda expression using ASM?
EDIT 01-08-2016: I added another method using the SerializedLambda class which does not required a 3-rd party software (i.e., ByteBuddy), you can read about it in the section titled: "Using SerializedLambda" bellow.
Original Answer: Problem Explanation + Solving it Using ByteBuddy
The accepted answer did not contain concrete information about how to actually read the lambda byte code at run-time via asm (i.e., without javap) - so I thought I would add this information here for future reference and the benefit of others.
assume the following code:
public static void main(String[] args) {
Supplier<Integer> s = () -> 1;
byte[] bytecode = getByteCodeOf(s.getClass()); //this is the method that we need to create.
ClassReader reader = new ClassReader(bytecode);
print(reader);
}
I am assuming that you already have the print(ClassReader) code - if not see the answers to this question.
In order to read the byte-code via asm you first need to give asm (via the ClassReader) the actual byte-code of the lambda - the problem is that the lambda class is generated at runtime via the LambdaMetaFactory class and therefore the normal method of getting the byte code does NOT work:
byte[] getByteCodeOf(Class<?> c){
//in the following - c.getResourceAsStream will return null..
try (InputStream input = c.getResourceAsStream('/' + c.getName().replace('.', '/')+ ".class")){
byte[] result = new byte[input.available()];
input.read(result);
return result;
}
}
If we look on the name of the class c via c.getName() we will see something like defining.class.package.DefiningClass$$Lambda$x/y where x and y are numbers, now we can understand why the above does not work - there is no such resource on the classpath..
Although the JVM obviously knows the bytecode of the class, sadly, it has no ready-made API that allows you to retrieve it, on the other-hand, the JVM has an instrumentation API (via Agents) which allows you to write a class that can inspect the bytecode of a loading (and re-loading) classes.
We could have written such agent, and somehow communicate to it that we want to receive the bytecode of the lambda class - the agent may then request the JVM to reload that class (without changing it) - which will result in the agent receiving the byte-code of the reloading class and returning it back to us.
Luckily for us there is a library called ByteBuddy that have such agent already created, using this library - the following will work (if you are a maven user include dependencies for both byte-buddy-dep and byte-buddy-agent in your pom, also - see notes bellow about limitations).
private static final Instrumentation instrumentation = ByteBuddyAgent.install();
byte[] getByteCodeOf(Class<?> c) throws IOException {
ClassFileLocator locator = ClassFileLocator.AgentBased.of(instrumentation, c);
TypeDescription.ForLoadedType desc = new TypeDescription.ForLoadedType(c);
ClassFileLocator.Resolution resolution = locator.locate(desc.getName());
return resolution.resolve();
}
Limitation:
- Depending on your jvm installation you may have to install the agent via command line (see ByteBuddyAgent documentation and Instrumentation documentation)
New Answer: Using SerializedLambda
If the lambda you are trying to read implements an interface that extends Serializable - the LambdaMetafactory class actually generates a private methods called writeReplace which provides an instance of the class SerializedLambda. This instance can be used to retrieve the actual static method that was generated using the LambdaMetafactory.
So, for example here are 2 ways to have a "Serializable Lambda":
public class Sample {
interface SerializableRunnable extends Runnable, Serializable{}
public static void main(String... args) {
SerializableRunnable oneWay = () -> System.out.println("I am a serializable lambda");
Runnable anotherWay = (Serializable & Runnable) () -> System.out.println("I am a serializable lambda too!");
}
}
In the above examples both oneWay and anotherWay will have a generated writeReplace method which can be retrieved using reflection in the following way:
SerializedLambda getSerializedLambda(Serializable lambda) throws Exception {
final Method method = lambda.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(true);
return (SerializedLambda) method.invoke(lambda);
}
If we look at the javadoc of SerializedLambda we will find the following methods:
public String getImplClass():
Get the name of the class containing the implementation method.
Returns:
the name of the class containing the implementation method
public String getImplMethodName():
Get the name of the implementation method.
Returns:
the name of the implementation method
Which means that you can now use ASM to read the class containing the lambda, get to the method that implement the lambda and modify/read it.
You can even get a reflective version of the lambda using this code:
Method getReflectedMethod(Serializable lambda) throws Exception {
SerializedLambda s = getSerializedLambda(lambda);
Class containingClass = Class.forName(s.getImplClass());
String methodName = s.getImplMethodName();
for (Method m : containingClass.getDeclaredMethods()) {
if (m.getName().equals(methodName)) return m;
}
throw new NoSuchElementException("reflected method could not be found");
}
A lambda compiles to a static method with a synthetic name. So to read the code using ASM, you would reverse engineer the method name ... then read it like any other method.
But if you just want to look at the bytecode for the lambda, it is simpler to use javap.
For some special use-case I have a small utility to load Java classes from jars using a dynamic class loader DynamicClassLoader. This works fine for Java classes contained in jars. Loading Scala classes from a jar also works without problems. However, instantiating the loaded Scala class leads to the following exception. It looks like the Scala class has private default constructor? Note the compiled Scala class name ending with $
java.lang.IllegalAccessException: Class XXX can not access a member of class ScalaClassYYY$ with modifiers "private"
The snippet below illustrates the idea of what I'm trying to achieve and gives a bit more context. The exception happens at the annotated line:
// deploy and register the new code
byte[] jarBytes = (byte[]) ((Object) message.getAttachment("jar"));
String registerClassName = message.getAttachment("register");
logger.debug("the register is '" + registerClassName + "'");
DynamicClassLoader loader = new DynamicClassLoader(jarBytes);
Class<?> registerClass = loader.lookUp(registerClassName);
// ===> this is where the java.lang.IllegalAccessException happens
IRegisterExecutor registerExecutor = (IRegisterExecutor) registerClass.newInstance();
registerExecutor.register();
Any ideas how to fix?
Obviously, you need to make the default constructor public (it won't work for Java classes without a public default constructor either). E.g.
class ScalaClassYYY() {
...
}
or if you want primary constructor to take some arguments,
class ScalaClassYYY(arg1: Int) {
def this() = this(0)
}
But from
Note the compiled Scala class name ending with $
it seems like you are actually trying to instantiate a Scala object:
object ScalaClassYYY { ... }
In this case, you shouldn't create a new instance and instead use the existing one:
(IRegisterExecutor) registerClass.getField("MODULE$").get(null);
EDIT:
I don't see in your answer how you add a default public constructor to a Scala class that does NOT require any parameters.
A class (not an object) that doesn't require any parameters has a default public constructor already (my first example).
Actually in Java all classes by default offer a public default constructor
No. Only those classes which have no constructors which take arguments.
remove the "(it won't work for Java classes without a public default constructor either)" because it is wrong
The documentation for Class.newInstance() says
IllegalAccessException - if the class or its nullary constructor is not accessible.
So I am pretty sure it's right. If it does work for Java classes without a public default constructor, this seems to be a major bug in the class loader you use. You can test it with a Java class which looks like this:
public class TestClass implements IRegisterExecutor {
public TestClass(int dummy) {}
// some implementation for IRegisterExecutor methods to get it to compile
}