Xposed - Legacy thread. Don't panic, Xposed is still here.

Status
Not open for further replies.
Search This thread

rovo89

Senior Recognized Developer
Jan 4, 2012
2,585
81,434
Do you have Busybox installed? Or rather, do you have an /sbin/sh executable? The script is executed by /sbin/sh, which is linked to /sbin/busybox on my phone.
 

rovo89

Senior Recognized Developer
Jan 4, 2012
2,585
81,434
I have the same.. but I'm not sure whether the link from /sbin/sh is automatically there. So I have checked the LPQ stock image and found out that /system/bin/sh is a part of it. I changed the references to it. Could you try that please?
 

Attachments

  • XposedInstaller.apk
    66.2 KB · Views: 3,216
Installation succes !

First message was:
Screenshot_2012-04-06-21-09-33.png



So i thought install again and i got:
Screenshot_2012-04-06-21-10-43.png


After that the program still said not installed, but i decided to reboot and after thatthe program said installed.
 
  • Like
Reactions: boricua6

rovo89

Senior Recognized Developer
Jan 4, 2012
2,585
81,434
Thanks for the feedback! I hadn't thought of the commands like touch and chown that are executed by the script. I have also other versions of these. So now I changed it to always use the versions from /system/bin. I got the same errors then and corrected them. Also, the versions are now updated when you install.

I will update the first post with the new installer. You will probably need to reinstall, because the permissions could not be set correctly.

PS: Which ROM is that?
 

rovo89

Senior Recognized Developer
Jan 4, 2012
2,585
81,434
Battery impact should be close to zero. Xposed does not require any services or additional wakelocks. Also it does no polling (frequent checks for a certain state). There is a small initialization phase, afterwards it gets only called when one of the hooked methods is about to be executed. So it does not prevent deep sleep because it gets only triggered by apps/services running anyway.

This of course depends on how the modules are implemented. The red clock example hooks a specialized method that is only called when the clock text is updated (once a minute). If it instead hooked a very generic method like setText, it would be called more often and it would have to execute more new code to find out if it has to do something.

The same applies to performance. If the developer is specific with the method hooks and the ratio of original to additional code is sensible, the impact will be low.

These are mainly thoughts as I could not test battery impact over a longer period yet (too much develop and restarts etc). But I did not feel a performance impact from the clock example, so the framework should be fine.
 
  • Like
Reactions: Rosli59564

Jecht

Member
Mar 25, 2011
27
1
So I've installed the apk and red clock test one aswell. It works fine on CM9 and seems like a great project. :)
 

wooki

Senior Member
Just a quick (maybe dumb) question/idea:
Would a module build with PDroid work with this?
I think PDroid changes some framework stuff and so we could have an easy way to intigrate it's privacy fetaures into our android rom (without using this "smali" patch thing on every rom update-zip we install)

Link to the thread is here:
http://xdaforums.com/showthread.php?t=1357056

(And here ICS specific thread: http://xdaforums.com/showthread.php?t=1554960 )


PDroid is changing framework.jar, services.jar, core.jar i think!

Thank you for reading and sorry for my bad english :(
 
Last edited:
  • Like
Reactions: pan.droid

mljjlm

Senior Member
Mar 7, 2010
385
68
Copenhagen
This could also be used for theming right? I mean, make apps search for graphics in other places than it normally would?
 

Tungstwenty

Senior Member
Nov 1, 2011
1,830
4,512
@rovo89
Excellent idea and implementation, plus great tutorial for those not familiar with reflection, etc.

I can't wait to spare some time to take this for a test drive.
I already have a use case for it: put callbacks on the Power Manager so that in conjunction with BetterBatteryStats tool, one can not only know the process and WL that is responsible for the CPU being awake, but also activate an Xposed module that can catch all acquire/release invocations and log the stack trace so it's possible to know the exact java/smali places to look for WakeLock issues.


I've already browsed the (ASOP) PowerManagerService source and as far as I can see, a good candidate place could well be directly in Power.acquireWakeLock and .releaseWakeLock (this isn't necessarily the best place depending on the aggregation one wants to do, but let's suppose this is what's intended, for argument's sake :)).

This brings me to my question: is it possible in your implementation to wrap native methods as well? Or must I go a bit upstream so I'm putting callbacks on "regular" java methods?
 

rovo89

Senior Recognized Developer
Jan 4, 2012
2,585
81,434
So I've installed the apk and red clock test one aswell. It works fine on CM9 and seems like a great project. :)
Good to know that even the binaries are compatible for Stock, AOSP and CM9! That's what I hoped.

Just a quick (maybe dumb) question/idea:
Would a module build with PDroid work with this?
I didn't have the time to look at it in detail. From what I saw, most of the patches are for creating new classes and only a few things modify the existing code. In Xposed, some of the modifications might have to be done a bit differently (as you cannot change the code inside a method), but I think this should be possible.

This could also be used for theming right? I mean, make apps search for graphics in other places than it normally would?
Absolutely! Actually, I have already implemented new methods that make it very easy for developers to change some of the resources (e.g. strings and booleans). Unfortunately, with these changes the applications list in the settings crashes and I'm trying not to work around this, but fix the root cause. And for this, I have already spent like 30-40 hours of debugging in the past days. It's probably a stack corruption and very hard to debug.

I already have a use case for it: put callbacks on the Power Manager so that in conjunction with BetterBatteryStats tool, one can not only know the process and WL that is responsible for the CPU being awake, but also activate an Xposed module that can catch all acquire/release invocations and log the stack trace so it's possible to know the exact java/smali places to look for WakeLock issues.

That sounds like something I could use too! :) What I would also like to know: Which wakelocks (from which apps) where active at what time?

This brings me to my question: is it possible in your implementation to wrap native methods as well? Or must I go a bit upstream so I'm putting callbacks on "regular" java methods?
I think it should work.. but I haven't tried yet. As mentioned, I'm currently busy with bug hunting. Afterwards, I will have a look at this.
 
  • Like
Reactions: Rosli59564

_JKay_

Retired Recognized Developer
Aug 12, 2010
5,495
14,689
Great work! Congratulations and thanks!

For minor mods this is great! Replacing methods on java level instead of files on the smali level.

For larger mods I think this could quickly become rather complex to read and maintain.

How would you add new member variables to a class? Add new methods to a class?

Can one access existing member variables? Maybe use setAccessible(true) ?

Sorry for the noob questions... Just trying to find it's possibilities and limits...

I think I have to try this! :)

Thanks

Sent from my GT-N7000 using xda premium
 
Last edited:
  • Like
Reactions: r1m and micmaccc

Tungstwenty

Senior Member
Nov 1, 2011
1,830
4,512
Lol, I wouldn't be expecting JKay apologizing for noob questions :D

In reflection it's not possible to add methods or fields, although accessing existing member fields is just the same as accessing methods.
Have a look at the Reflection tutorial for a quick glance of what's possible to do. Then, for what's not (e.g. instrumentation or dynamic injection of new fields / methods), the pressure's on rovo89 to add it to his framework :p

I'm not familiar with your internal implementation, but lots of stuff should fit this model. When you're adding a wrapper to an existing class' method, you could maintain on your side (the wrapper) additional info and additional methods, and have them used whenever the right conditions are needed. And if multiple objects of the same type (or not) are wrapped by a single class or object of yours, you could still use the original object reference as a key to a Map where you store per-object stuff. Theoretically, most of the stuff should be possible ...

Performance might be something to consider (as well as code maintainability as you mentioned), but provided nothing is called lots of times in succession, the reflection overhead should be relatively low within all the code. Also, the main concern is power usage / deep sleep - where lots of custom lock screens, etc. put a lot of stress on power management - but on that front nothing would change.
 
  • Like
Reactions: Rosli59564

_JKay_

Retired Recognized Developer
Aug 12, 2010
5,495
14,689
Lol, I wouldn't be expecting JKay apologizing for noob questions :D

In reflection it's not possible to add methods or fields, although accessing existing member fields is just the same as accessing methods.
Have a look at the Reflection tutorial for a quick glance of what's possible to do. Then, for what's not (e.g. instrumentation or dynamic injection of new fields / methods), the pressure's on rovo89 to add it to his framework :p

I'm not familiar with your internal implementation, but lots of stuff should fit this model. When you're adding a wrapper to an existing class' method, you could maintain on your side (the wrapper) additional info and additional methods, and have them used whenever the right conditions are needed. And if multiple objects of the same type (or not) are wrapped by a single class or object of yours, you could still use the original object reference as a key to a Map where you store per-object stuff. Theoretically, most of the stuff should be possible ...

Performance might be something to consider (as well as code maintainability as you mentioned), but provided nothing is called lots of times in succession, the reflection overhead should be relatively low within all the code. Also, the main concern is power usage / deep sleep - where lots of custom lock screens, etc. put a lot of stress on power management - but on that front nothing would change.

Thanks.. So it's kinda like extending a class in a package.

So I would have to rewrite the whole method? Or can I subclass it and call it's super class?

Sent from my GT-I9100 using xda premium
 

Tungstwenty

Senior Member
Nov 1, 2011
1,830
4,512
You don't need to rewrite it, but you're limited to either entirely replacing it with your own code (discard calling the original code in your wrapper), or invoking the original method and having your own instructions executing before and/or after the original stuff. Much like extending a class, yes, but where you're essentially overriding existing methods and in your implementation optionally calling the super(...) or not depending on what you want. You can also create extra methods in your own code, but they won't belong to the original class - they can only be called by your own code or attaching listeners for that, etc.

One thing you can't do, for instance, is calling the original method but ignore a certain instruction in there, you don't have that kind of granularity.
Well, with some creativity it might be worked around. For instance, if the method you're wrapping - but reusing the original as well - at some point inserts a value in a private Map field, you could call the super(...) method provided that before you created a callback as well on the Map.put(...) of that object so you're able to ignore the particular instruction that happens within the original method. Not sure if I make myself clear ...

(all this is based on my reflection knowledge and also the samples mentioned, I didn't have the chance to play with the framework yet)
 
  • Like
Reactions: rovo89 and _JKay_

rovo89

Senior Recognized Developer
Jan 4, 2012
2,585
81,434
Wow, I actually wanted to give JKay a heads up on my project, but now he came here himself. Great :)

Tungstwenty explained it already very well. Subclassing is basically what you can do with method hooking and you have an equivalent to super. You can of course access the methods and fields in any class (as long as you are in the correct process) and also set the values (works for private fields and I think even final ones). This is all standard reflection.

Adding new members and methods to a class is not easily possible. I might see whether I can do this somehow with native code, but there would have to be a use-case. For example, if you want to save something for every instance of a View, you could create a static Map<View,Something> in the module coding. Instead of using reflection to get/set the field value, just use map.get/put(view). I cannot imagine any use of new members outside of module coding. And you add new methods to the module instead of the class. You will get the "this" reference as parameter "thisObject" in callback methods anyway, so you can just pass it on to other methods in your module.

I agree that it would be good to replace some method calls only inside certain methods. You can do it, but it would require quite a bit of context checking. For common cases like this, I could implement helpers that would make it easier for developers. That's why you can register a method that should be called when a new package is being loaded (in that package's thread) - it can be done in other ways, but it is so common that a helper makes sense.

@lonelime: Do you mean resources like the battery icon etc.? That's what I'm currently working on. I finally - after some more hours of debugging - found the (really unobvious) reason why the applications list in the Settings app crashed and fixed it. So I can concentrate now on the resource loading stuff.

Current status: Replacing a string, boolean or integer resource from either the framework or a single app with a new value defined in the module's coding works fine. The approach I finally decided to take is one that replaces Resources instance returned by e.g. Activity.getResources() with a new class that inherits from Resources. This way, I do not need to hook getString(), but can use normal method overriding. You set the replacement values usually during startup. Then they are stored in a HashMap, which is queried in getString() etc. Apart from the (cached) creating of this instance, it only adds two HashMap lookups to the calls. And the good thing: This works with a constant time, no matter how many resources you replace!

You can look at this example to see how easy it is to replace a resource:
Code:
	public static void init(String startClassName) {
		if (startClassName != null)
			return;
		
		try {
			XResources.setSystemWideReplacement("android", "bool", "config_animateScreenLights", false);
			XResources.setSystemWideReplacement("android", "bool", "config_unplugTurnsOnScreen", false);
			XposedBridge.hookInitPackageResources(Example.class, "handleInitPackageResources", Callback.PRIORITY_DEFAULT);
		} catch (Throwable t) {
			XposedBridge.log(t);
		}
	}
	
	@SuppressWarnings("unused")
	private static void handleInitPackageResources(String packageName, XResources res) {
		// replacements only for SystemUI
		if (!packageName.equals("com.android.systemui"))
			return;
		
		res.setReplacement(0x7f080083, "YEAH!"); // WLAN toggle text. You should not do this because the id is not fixed. Only for framework resources, you could use android.R.string.something
		res.setReplacement("com.android.systemui:string/quickpanel_bluetooth_text", "WOO!");
		res.setReplacement("com.android.systemui", "string", "quickpanel_gps_text", "HOO!");
		res.setReplacement("com.android.systemui", "integer", "config_maxLevelOfSignalStrengthIndicator", 6);
	}

This adds the CRT off effect, keeps the device from turning on when you unplug it, modifies the text of some statusbar toggles (demonstrating different ways to call it) and gives you 6 instead of 4 bars for the signal strength.

Before releasing this, I will also try to implement replacing other types of resources. For things like Layouts and Drawables, you will most likely add the replacement to your module as a normal resource and then activate some kind of redirection. No release date though, I might not find the time for it in the next few days (for example, I could use some sleep ;)).
 
  • Like
Reactions: Tungstwenty and r1m

Tungstwenty

Senior Member
Nov 1, 2011
1,830
4,512
I finally had some time to install this and try out the 2 mods you created (not creating my own yet, sorry)

I noticed a few stacktraces on my logcat. Most if not all are not related with Xposed, only eventually the Clock modification might be since it's from when I had the red clock active (currently I only have the CRT one).
Care to take a look at the attached traces? Probably nothing related with you, but nevertheless.

Most of them have "dalvik.system.NativeStart.main()" at the root of the stack, and a method invocation soon after - I assume this is normal and part of your global hooking logic. The rest of the stack till the exception is just expected errors in some situations (network timeout, apk bugs, etc.)
In others, there is reference to "injection" but it looks as it's related with the applications themselves (e.g. roboguice library), not Xposed.
The ones where I'm in doubt are java.lang.IndexOutOfBoundsException and "Uncaught remote exception! (Exceptions are not yet supported across processes.)", both apparently related with the TIME_TICK broadcast and therefore might be the red clock mod (???)
Finally, there's also an ARM fault with native stack trace, you might also want to take a look at it since there are references in the stack to mangled function names such as "_Z14dvmCallMethodVP6ThreadPK6MethodP6ObjectbP6JValueSt9__va_list", "_Z15dvmInvokeMethodP6ObjectPK6MethodP11ArrayObjectS5_P11ClassObjectb", ...

One other thing:
In some of the traces, there is no call to the 2 reflection methods near the beginning. This happens in some of the NativeStart.main() roots, and also on stacks ending with "java.lang.Thread.run()".
Do you know whether in both of these situations the hooks are still applied, even if no mention of "method.invoke..." is found?


About the resources, let us know as soon as there's a usable version :)
Are you considering also binary resources such as .pngs, which would reside in the mod and be passed to the target app as if it lived there?
One suggestion I also have is for you to make available helper methods for stuff such as fetching fields or methods and make them accessible/public all in one go, and that kind of stuff that might ease up a bit the setting up of reflection.


PS: About changing final fields, that you mentioned earlier, I don't think that's possible. Although it's not 100% deterministic, in practice most of the times the compiler inlines the constant value in the places that access the field, so even if you change it (which is possible), the methods that uses the field already has the constant in their bytecode. Check e.g. this link for some info on this: http://stackoverflow.com/questions/...-private-static-final-field-didnt-do-anything

Cheers!
 

Attachments

  • StackTraces.txt
    50.3 KB · Views: 135
Status
Not open for further replies.

Top Liked Posts

  • There are no posts matching your filters.
  • 638
    Xposed 2.4 beta1/beta2

    This is Xposed version 2.4 beta1. The main new features and fixes in this version are:
    • Support for Android 4.4 (KitKat)
    • Significant performance improvements of the framework
    • Viewer for the debug.log in the installer
    • Check in the installer whether Xposed is actually active and working

    First of all, I would like to thank the 45 people who donated to get me a Nexus 5, from a little "thanks" to huge amounts of money. I was really impressed and hope you like this update.

    In detail:
    Xposed should now fully support KitKat. As mentioned, that wouldn't have been possible at this time without your support.
    Modules should continue to work if they don't rely on AOSP internals that have changed in KitKat. One example: It seems that the battery icon is no longer an (animated) image, but a Java implementation. Obviously, any modules that try to replace the battery image will no longer work. The Xposed framework can't do anything here, the module needs to be rewritten. Therefore, if some of your modules don't work, please get in contact with the module author first. You will probably see an error in the new debug.log viewer in this case.
    Xposed isn't compatible with ART, I can't say yet whether it will be in the future (will require a major rewrite if possible at all). As you would get into a bootloop if you try to combine Xposed+ART, Xposed automatically resets the choice to "Dalvik". If you want to test ART, you must uninstall the framework.

    The performance improvements apply to the very core of Xposed, the method hooks, in all Android versions. In a test app developed by @exidler, the overhead per call used to be ~71 μs (= 0.071 ms) per call to a hooked method (with one empty callback handler) on my Galaxy S2. Now it's ~13 μs (= 0.013 ms). That's a relative improvement of factor ~5.5x. Thanks to @exidler for the research and several suggestions! I have sent a pre-beta to @kamso, who had reported lags with older versions. Now everything works fine for him. Anyway, I wouldn't say that Xposed had bad performance before. Keep in mind that we are talking about significantly less than a millisecond here.

    The debug.log viewer should give a quick impression whether Xposed and modules could be loaded fine. It also includes options to save the log to SD card (so it's easier to transfer it to a PC etc.) and send it via mail.

    The Xposed Installer now checks whether the latest version of the framework is active. If not (e.g. because it's not installed yet, you forgot to reboot or something in Xposed doesn't work), you will see a warning in the welcome screen and at the top of the module list.

    Finally, there were some other minor improvements and fixes and new/updated translations.


    Developers:
    As a reminder, please keep the debug.log clean. It's only helpful if it's not as spammed as logcat. You should only use XposedBridge.log() for error messages and other unexpected situations. If everything runs fine, it shouldn't write anything to the log. If you really need to keep some logging in published builds, please use either logcat or make it an opt-in options (i.e. disabled by default and the user enables it if he runs into problems).

    Apart from that, there was a little API change: https://github.com/rovo89/XposedBridge/commit/3c18f6f6bd4e0ec57898b3b3a79b5584d0396054
    I assume that very few modules use the "extra" field to transfer information between beforeHookedMethod() and afterHookedMethod(). If you do, simply replace it by getExtra().

    Layout inflation hooks now also work if the layout has been included in other layouts. That's actually a pretty tricky use-case for the "extra" parameter mentioned about (and other tricky technologies).

    If for some reason you need to determine the active XposedBridge version in your module, you can use XposedBridge.XPOSED_BRIDGE_VERSION.

    findMethodBestMatch() now also looks for protected and package-private methods in superclasses. That's mainly useful if you use the callMethod() or callStaticMethod() helper.

    UPDATE: (beta2)
    The new beta should fix the "read-only filesystem" errors. If you used to experience them, please try this version. Otherwise, there is no need (and no advantage) to update.

    UPDATE:
    The final version is out, please use it instead (see first post / in-app installer).
    479
    The ART of patience

    Regarding ART possibly becoming the default runtime engine: I think that's good news because it means that we will get a stable version of ART then. I'm reluctant to work further on ART support at the moment for mainly three reasons:

    1. Time. I used to spend every evening and every weekend for Xposed, either to give support here (often answering the same questions again and again), writing code or researching about bugs or new ideas. As you may have noticed, there are now days or even weeks where I don't even log on to XDA, and I'm actually glad about this.

    2. Experimental software is bound to contain bugs, even severe ones. There is a reason why Google didn't make this choice available for the typical user (and keep in mind, we are not typical users). I neither want people to blame Xposed if their phone starts acting up nor do I want to hunt bugs which are caused by a runtime engine that is explicitely labelled as not finished yet.

    3. As long as ART is experimental, it's much easier to make big changes to the code. Once a final version is out and used by the masses, quality engineers we be much more careful not to break things. That means that Xposed for ART on 4.5 (or whatever it will be called) might need to be completely different than for ART on 4.4. More variants means more time for maintenance. And I don't feel like pushing something out now just to drop support again in a later version. There is not enough benefit of using ART at the moment to justify that.

    You know, I had already worked on ART support and spent several dozens of hours reading the code, looking for ways to hijack it, implementing my ideas, doing trial and error and starting again from the beginning. I finally had my Nexus 5 boot with Xposed in early December and quickly tested the App Settings module. I'm happy about that, but I also know that this was just a very experimental version, less ready than ART itself. It is totally hacked together and only tested with the stock ROM. ART is quite complex and has several different modes. It's not worth giving the current development to someone else before I have tested these things on my phone, where I can debug much better than instructing someone else to do it. It also requires rewriting app_process to be a light executable again, which loads either the Dalvik or ART Xposed library, depending on your settings. That would require changes in the installer as well, etc. etc.

    So you see, there is still lots of work to do. At the moment, I'm not actively working on it, but trying to get some other things fixed (e.g. LG ROMs) or improved (installation via recovery, better installation feedback in case root access failed, static Busybox package). And as I said, I do have other things in my life as well. It's not about money, that's what I have my full-time job for. I work on Xposed for fun (and maybe a bit for the reputation ;)), so the best way to ensure that I keep on working on it is not taking away the fun part of it. Don't pressure me like it was my duty to implement something ASAP (!!!), be patient even if it takes a bit longer until I answer and join the volunteers who help answering basic questions here so I don't have to. Thanks!
    317
    General information on Xposed has been moved to this thread: http://xdaforums.com/xposed/xposed-installer-versions-changelog-t2714053
    The FAQ has been moved to this thread: http://xdaforums.com/xposed/-t2735540
    Questions, suggestions, bug reports and so on can be posted in the Xposed General forum (for the installer/framework/development only) and in the Xposed Framework modules forum (for anything module-related).
    222
    Xposed Framework Installer (Flashable Zip)

    Announcement: Xposed Framework v2.5+ comes with an option to flash its own install zip via recovery, making my package obsolete. I'll leave them up for posterity; could be useful should the need arise for downgrading on some devices. Cheers all! 10000 downloads is pretty cool. :)

    Xposed Framework v2.2+ has fixed JB4.3 installation and v2.4+ has added support for KK4.4, but for those that still want it, or cannot install via the APK due to /system write protection like HTC's S-ON, here is an updated zip frontend method for installing the framework; now for Xposed Framework v2.4.1.

    You MUST have the Xposed Installer APK installed FIRST. The zip will detect if you do not and stop.

    Flash this in recovery and my frontend script (the update-binary) will detect the correct architecture and SDK version to use the appropriate Xposed app_process and busybox builds (x86, armv5, v6 and v7 & sdk 15 and 16+ supported), and should detect the uid of the Xposed Installer APK on-the-fly and set up the required files with it.

    It leaves a log behind in /data/local/tmp/xposed-log.txt either way with more details about how it went. :cool:

    It also unpacks Xposed-Disabler-Recovery.zip to /sdcard/ (or /sdcard/0/ if it exists) to be as close to the APK install method as possible. For those wanting another method to reactivate after a ROM update or toggle Xposed disabled/enabled, @amishxda has also created a cool "Xposed toggler" zip here.

    Note: Xposed Framework files and the install.sh used are the work of @rovo89 and @Tungstwenty; I have only created a recovery flashable zip to function as an alternative frontend for the framework installation process. I take no credit for their fantastic work.


    P.S. If you found this handy then please check out my Odds and Ends thread for more flashable goodness. :D

    5351 downloads of v2.1.4 when removed. 1049 downloads of v2.2 when removed.
    193
    Xposed 2.5 final

    This is Xposed version 2.5 (final). The main new features and fixes in this version are:
    • Rewritten framework installation/uninstallation
      • Uses interactive su (via libsuperuser) to provide improved compatibility with different Superuser apps
      • Better feedback when root access fails (doesn't freeze the app anymore)
      • Offers installation via custom recovery (CWM/TWRP), either flashing the file automatically or manually
    • Safemode to disable Xposed with hardware keys to get out of (most) bootloops
    • Compatibility with Sony/LG ROMs (4.3 and 4.4), Meizu ROMs (4.4)
    • Debug setting to disable resource hooking as a temporary workaround for incompatibilities with some theming engines (not all modules can be used in this mode)
    There are also other improvements and fixes, especially many translations updates.
    In case you get a message "Segmentation fault" during installation, you can now download an additional app which provides statically compiled versions of BusyBox (a lot bigger, but should work with every ROM). It's not needed otherwise.

    Quick explanation of the safemode: It was developed by @Tungstwenty and makes it possible to disable Xposed by repeatedly pressing one of the hardware buttons during early startup. The phone will vibrate twice when the first key press has been detected. Then you have five seconds to press the same button four more times. Each key press will be confirmed with a short vibration; the final one with a long vibration. It creates /data/data/de.robv.android.xposed.installer/conf/disabled, which prevents most of Xposed's actions (e.g. no hooks are made and no modules are loaded). There's no 100% guarantee that this will get you out of a bootloop, but in most cases it should.

    As always, you can download it via the in-app updater or from http://dl.xposed.info/latest.apk.