I feel like I'm missing a piece of the puzzle here.
Basically, I'm trying to hook a constructor with a Context for an argument. The field I'm trying to access is initialized in the same class but outside of the constructor. Neither the constructor nor the field are static, but they are both private (if that makes a difference).
But for whatever reason I just can't find the field in order to modify it (the module throws NoSuchFieldError). What am I doing wrong, and is there a workaround?
My code:
Code:
public void initZygote(final StartupParam sp) throws Throwable {
if (devicePlatformVersion >= 4.0) {
final Class<?> clsViewConfig = ViewConfiguration.class;
try {
final Constructor<?> cstViewConfig = XposedHelpers.findConstructorExact(clsViewConfig, Context.class);
XposedBridge.hookMethod(cstViewConfig, new XC_MethodHook(XCallback.PRIORITY_HIGHEST) {
protected void beforeHookedMethod(final MethodHookParam mhp) {
XposedBridge.log("Inside beforeHookedMethod routine from ViewConfiguration callback....");
XposedHelpers.setBooleanField(mhp.thisObject, "sHasPermanentMenuKeySet", true);
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
try {
XposedHelpers.findAndHookMethod(clsViewConfig, "hasPermanentMenuKey", XC_MethodReplacement.returnConstant(false));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
And here's the target class:
https://github.com/android/platform...core/java/android/view/ViewConfiguration.java
Thanks!
I may have found out why the error is being thrown.
The setBooleanField method tries to call the findField method. findField returns the field as a Field object back to the calling method (setBooleanField). However, if the field is null, findField throws a NoSuchFieldError.
From the XposedHelpers class:
Code:
public static Field findField(Class<?> clazz, String fieldName) {
StringBuilder sb = new StringBuilder(clazz.getName());
sb.append('#');
sb.append(fieldName);
String fullFieldName = sb.toString();
if (fieldCache.containsKey(fullFieldName)) {
Field field = fieldCache.get(fullFieldName);
if (field == null)
throw new NoSuchFieldError(fullFieldName);
return field;
}
try {
Field field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException e) {
fieldCache.put(fullFieldName, null);
throw new NoSuchFieldError(fullFieldName);
}
}
Since the field I'm trying to find has only been initialized, it doesn't yet have a value, making findField catch and throw an exception that isn't exactly true. There is such a field, it's just hasn't been set.
Is anyone aware of this potential problem?
I'm going to see if I can get my code to work by catching the exception, hiding the error, and seeing if the field can, in fact, be set with a true.
You might want to open an issue at GitHub. Regarding your problem, couldn't you use afterHookedMethod instead of beforeHookedMethod to set the variable to the value you want?
Thanks for the reply!
I'm using the "before" variant as I want to set the field before the code inside the constructor is executed. Unless I'm overlooking something?
I recently switched to the findAndHookConstructor method to help simplify things a bit, and I tried getting the context from args[0] to see if I could set the field with that. But no matter what I try, NoSuchFieldError keeps getting thrown.
Sent from my SAMSUNG-SGH-I747
(I suggested using afterHookedMethod if the constructor didn't access sHasPermanentKey. Since it does, ignore that suggestion. )
If I understand what you want to do correctly, you could hook the hasPermanentMenuKey method instead?
Anyway, after reading your question again and checking the classes, I think the problem is that the field really isn't there.
getField is just a helper that uses normal reflection, and it should definitely find the field if it exists. I'm guessing you're using a different Android version than the one you're checking the source for, or you're not running AOSP and it's been modified.
If that doesn't help, you could decompile framework.jar (if memory serves right) and make sure the field exists.
I have the method that returns a boolean hooked already, and that works fine. However, many apps use the "get" method to generate a new configuration from the constructor when a context is provided. Hence why I also want to hook the constructor.
I'll definitely find out if my device actually has the field tonight.
Sent from my SAMSUNG-SGH-I747
Well. This explains a lot.
https://github.com/CyanogenMod/andr...core/java/android/view/ViewConfiguration.java
I feel like an idiot now. I have no idea why I just automatically assumed that CM would have kept that field from AOSP. Well, now I just need to dig around in CM's source for a bit.
One more question:
Is there a way to programatically check to see which flavor of Android ROM the user is running? I know there's a check for version/API level, but is there a better way than, say, looking for a file only found in CM releases to verify the user is in fact running CM (as opposed to AOSP, Omni, and anything else that has an original base)?
Thanks!
JJohnson1988 said:
One more question:
Is there a way to programatically check to see which flavor of Android ROM the user is running? I know there's a check for version/API level, but is there a better way than, say, looking for a file only found in CM releases to verify the user is in fact running CM (as opposed to AOSP, Omni, and anything else that has an original base)?
Thanks!
Click to expand...
Click to collapse
As far as I know, the only way would require you to would require you to know every ROM out there. Usually it's enough to just use a try/catch statement for each ROM dependent hook/action.
Hello,
Please consider the following scenario
Code:
public class Document {
...
protected boolean dirty;
...
void setDirty(boolean value) {...}
public boolean getDirty() {...}
}
public class DocumentManager {
...
public Document getDocument(String Id) {...}
...
}
Now I'm hooking getDocument method just fine, but I need to change the returned object's 'dirty' property.
How can I accomplish this?
Thanks in advance for your help.
Call XposedHelpers.setBooleanField(…) on a Document object for "dirty" or hook getDirty() and use param.setResult(…) (or the XC_MethodReplacement.returnConstant(…) shortcut) to set the result you want.
GermainZ said:
Call XposedHelpers.setBooleanField(…) on a Document object for "dirty" or hook getDirty() and use param.setResult(…) (or the XC_MethodReplacement.returnConstant(…) shortcut) to set the result you want.
Click to expand...
Click to collapse
XposedHelpers.setBooleanField did the trick. The class sometimes access the 'dirty' member without going through the getter. That's why I needed to change the field instead of hooking getDirty.
Thanks mate.
Cheers.
I need to implement a broadcast reciever that will fill variables for the methods my module will hook up.
But every thing that I tried out didnt work.
I tried to implement the reciever in the module class:
public class LogginExtra extends BroadcastReceiver implements IXposedHookLoadPackage {
But it says ClassNotFound.
Tried to make something with sharedPreferences, but the XSharedPreferences doesnt reads the prefs.
And I dont know how to solve this, if someone can help me I need to update 2 variables at the Module class (IXposedHookLoadPackage) from a broadcast reciever.
thanks in advanced.
caioketo said:
I need to implement a broadcast reciever that will fill variables for the methods my module will hook up.
But every thing that I tried out didnt work.
I tried to implement the reciever in the module class:
public class LogginExtra extends BroadcastReceiver implements IXposedHookLoadPackage {
But it says ClassNotFound.
Tried to make something with sharedPreferences, but the XSharedPreferences doesnt reads the prefs.
And I dont know how to solve this, if someone can help me I need to update 2 variables at the Module class (IXposedHookLoadPackage) from a broadcast reciever.
thanks in advanced.
Click to expand...
Click to collapse
The key to the solution is to realize the core of the module (the Xposed hooks) is not an application in itself. Instead its code runs as part of another application or as part of an Android system component. This is why XSharedPreferences is called 'shared'.
It depends on what your module is doing and when/where/how the code of you module runs, which solution is best.
Note that using XSharedPreferences isn't the holy grail either, as this solution might stop working in Android "L", because of new SELinux rules (which could affect quite some modules).
M66B said:
The key to the solution is to realize the core of the module (the Xposed hooks) is not an application in itself. Instead its code runs as part of another application or as part of an Android system component. This is why XSharedPreferences is called 'shared'.
It depends on what your module is doing and when/where/how the code of you module runs, which solution is best.
Note that using XSharedPreferences isn't the holy grail either, as this solution might stop working in Android "L", because of new SELinux rules (which could affect quite some modules).
Click to expand...
Click to collapse
Basically my module hook an Intent method, but I need a way to pass for the module the package name that it should look, and the package Ill get in a broadcast reciever, so, how can I pass a simple String variable for the module?? I understand what you said but still no clue to how to pass a variable from a reciever to the module itself.
caioketo said:
Basically my module hook an Intent method, but I need a way to pass for the module the package name that it should look, and the package Ill get in a broadcast reciever, so, how can I pass a simple String variable for the module?? I understand what you said but still no clue to how to pass a variable from a reciever to the module itself.
Click to expand...
Click to collapse
You can hook Intents at different places, which makes a difference, since this could be either within an application or within an Android component. Hooking within an application makes this simpler, since you will probably be able to use the application context to communicate.
Basically you can use some form of shared storage to pass information (which is what XSharedPreferences does) or inter process calls. Example of IPCs are intents and services, both if which require a proper Context instance to work.
The bottom line is that you first need to understand from where to where you need to communicate.
I am aware that I am not very concrete about what to do. You could take a look at the implementation of XSharedPreferences, which isn't very difficult to understand, or how for example XPrivacy does this, which is more difficult to understand: https://github.com/M66B/XPrivacy (basically the PrivacyManager class is used to fetch settings from a service implemented in PrivacyService class and running within Android).
But what you said about the XSharedPreferences, that it could possible stop working on L, makes me not wanting to use it, so here is my hook code:
findAndHookMethod("android.os.Bundle", loadPackageParam.classLoader, "getString", String.class, new XC_MethodHook() {
@override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (getExtra(loadParam.packageName)) {
String key = (String) param.args[0];
String value = (String) param.getResult();
getExtrasToSend().putString(key, value);
}
}
});
Basically it will grab every call to getExtras, of all packages, and when it get called it should check if the package that called, is the one I'm looking for (from the reciever part), I got 2 ideas, first one I'm testing right now, is I get a class wich holds a static field and method to the packageName variable, and I'm calling it with: (String)XposedHelpers.callMethod(Util.class, "getPackageName", null);
probably wont work, and I was thinking about hooking the method of my own reciever to get the variable in the module class, and use as static variable there.
Any of these should work? Is there a better way to make it??
caioketo said:
But what you said about the XSharedPreferences, that it could possible stop working on L, makes me not wanting to use it, so here is my hook code:
findAndHookMethod("android.os.Bundle", loadPackageParam.classLoader, "getString", String.class, new XC_MethodHook() {
@override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (getExtra(loadParam.packageName)) {
String key = (String) param.args[0];
String value = (String) param.getResult();
getExtrasToSend().putString(key, value);
}
}
});
Basically it will grab every call to getExtras, of all packages, and when it get called it should check if the package that called, is the one I'm looking for (from the reciever part), I got 2 ideas, first one I'm testing right now, is I get a class wich holds a static field and method to the packageName variable, and I'm calling it with: (String)XposedHelpers.callMethod(Util.class, "getPackageName", null);
probably wont work, and I was thinking about hooking the method of my own reciever to get the variable in the module class, and use as static variable there.
Any of these should work? Is there a better way to make it??
Click to expand...
Click to collapse
Static variables probably won't work, since the settings holder and the settings user probably run in different process spaces. You need either some kind of shared storage or an IPC mechanism to communicate the settings.
Is it possible to use files for that? or database? Im really lost, never work with that yet, and seems that there isnt any explanations on google.
caioketo said:
Is it possible to use files for that? or database? Im really lost, never work with that yet, and seems that there isnt any explanations on google.
Click to expand...
Click to collapse
Shared preferences does use an XML file, so yes. A database is possible too, but you need to make sure both the settings manager and the hook do have access to it, same as with using (XML) files. You'll need to take care of locking too, since multiple process will access the file or database.
M66B said:
Shared preferences does use an XML file, so yes. A database is possible too, but you need to make sure both the settings manager and the hook do have access to it, same as with using (XML) files. You'll need to take care of locking too, since multiple process will access the file or database.
Click to expand...
Click to collapse
I have broadcast receivers in my settings activity and my xposed module so they can communicate with each other. You need to setup your receiver in the xposed side programatically:
Code:
Context context = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
IntentFilter filter = new IntentFilter();
filter.addAction(XposedReceiver.RESET_ACTION);
filter.addAction(XposedReceiver.REFRESH_ACTION);
context.registerReceiver(mBroadcastReceiver, filter);
The problem is that I'm hooking the Intent class, and it dont have a context field for me to register the broadcast.
EDIT: I don't think Im being clear of what I need, I need to be able to set someway to send the package name to the module, I'll hook this methods:
findAndHookMethod("android.os.Bundle", loadPackageParam.classLoader, "getString", String.class, new XC_MethodHook() { @override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (loadParam.packageName.equals(PACKAGE_NAME_FROM_BROADCAST) {
String key = (String) param.args[0];
String value = (String) param.getResult();
getExtrasToSend().putString(key, value);
}
}
});
and I need to pass that PACKAGE_NAME_FROM_BROADCAST from a broadcast receiver, dont know the way to make it, tried static variables, xsharedpreferences, etc.
Cant get it working. and I dont know more what to try.
caioketo said:
The problem is that I'm hooking the Intent class, and it dont have a context field for me to register the broadcast.
EDIT: I don't think Im being clear of what I need, I need to be able to set someway to send the package name to the module, I'll hook this methods:
Code:
findAndHookMethod("android.os.Bundle", loadPackageParam.classLoader, "getString", String.class, new XC_MethodHook() {
@override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (getExtra(loadParam.packageName)) {
String key = (String) param.args[0];
String value = (String) param.getResult();
getExtrasToSend().putString(key, value);
}
}
});
and I need to pass that PACKAGE_NAME_FROM_BROADCAST from a broadcast receiver, dont know the way to make it, tried static variables, xsharedpreferences, etc.
Cant get it working. and I dont know more what to try.
Click to expand...
Click to collapse
First of all it is not a good idea to hook into android.os.Bundle, since this will impact the system performance significantly.
Moreover android.os.Bundle is used very frequently in applications and various Android components, meaning your hook will run in a variety of process spaces. Getting a Context in this Xposed hook will therefore often not be possible. If you really want to go this way, a service directly registered with the service manager is your only option, but my advice is to find another, less intrusive, way to do what you want.
Ok, the problem is that, my module needs to grabs all calls to "getExtras" ("getStringExtra", "getBooleanExtra", etc) to know all extras that the application will expect, than I'll pass it to AutoShare app, so you can customize and start an intent with all possible extras.
Is there any other way to grab the extras without hooking the Bundle or Intent? About the perform, its doing nothing if its without the right package, so will it still slow the performance???
Thanks for the repply.
caioketo said:
...
About the perform, its doing nothing if its without the right package, so will it still slow the performance???
Thanks for the repply.
Click to expand...
Click to collapse
A hook never does nothing, since there will always be code executed. The hook you are trying to use will be executed really a lot, so there will be significant performance problem.
The 'bundle' is a general 'message', which is used for a lot of things. You should find a way not to hook into the 'bundle', but into a higher level function.
Hi,
im a beginner i have small problem i have small application build where i can add stuff to the database and read it thats working fine for me but now for example i want to be it like example the output from the database is test test but i want it like Name : test Adress : test how can i fix this.
Thank you
Splitting Text
Not sure if I've understood correctly, but are you getting a String back from the database like this: "test test"?
If so you can use the String split() command to break your String into segments. For example:
Code:
String returned = //Get String from the database
String[] split = returned.split(" ");
String name = "Name: " + split[0]; //This contains your first word
String address = "Address: " + split[1]; //This contains your second word
How are you connecting to your database? Depending on how you connect, it is possible to return just a name, or just an address, rather than all columns in a row.
For example, using HQL (Hibernate Query Language) you could write something like:
Code:
SELECT address FROM person p WHERE p.name = "Harry"
This would return all the addresses of people called Harry from the table person
Hi, this is my first post here so please forgive me if I have put this in the wrong section, it was a bit confusing.
I have an application that takes the touch coordinates from onTouchEvent and and puts them in to an SQLite Database.
My three relevant classes:
Main class: TouchDetector.
Custom View class: TouchDetectorView.
Database class: TouchDatabaseHandler.
TouchDetectorView captures the touches and stores the x, y values in variables. I need to access the TouchDatabaseHandler class from this view class in order to send them to the database.
Constructor inside TouchDatabaseHandler class where data is sent to database:
Code:
public TouchDatabaseHandler(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
View class constructor.
Code:
public TouchDetectorView(Context context, AttributeSet attrs) {
super(context, attrs);
dbHandler = new TouchDatabaseHandler([COLOR="Red"][U]this[/U][/COLOR], null, null, 1);
}
What do I replace the this with to make my code work? The tutorial I was following had the dbHandler inside the onCreate but since I am in a View class I do not have on. I apologise if this is very vague, I am a beginner and would appreciate any help and/or feedback.