Preface
Xposed is a powerful framework for Android which can help solve many practical problems for Android developers. This article introduces the Xposed framework and how it works, and utilizes Xposed to analysis performance of competing Android apps without source code.
What is Xposed
Xposed is a framework that can customize the behavior of Android system without modifying any APK file on the phone. Instead of directly making changes to system, Xposed only provides the API to modify system behavior and let Xposed modules, i.e. plugins that can be installed or uninstalled, to do the actual customization job. Through Xposed framework, Xposed modules providing various features are completely decoupled from Android ROM and can be used on different system versions or even different ROMs without any modification. This also allow Xposed modules still work when the system is upgraded. More conveniently, all changes Xposed module made to the system are totally stored in memory, if you want to disable a feature, you only need to disable the Xposed module, and then restart the phone, you don't need to flash ROMs any more.
Some famous Xposed modules
So what can Xposed module do? Let's checkout some famous Xposed module below:
- XPrivacy: Allows controlling permissions of every app, for example, denying some apps from reading contacts, SMS;
- Keepchat: Stores snapchat photos you viewed, preventing them being erased by snapchat;
- Vine Downloader: Adds a 'download' button to download videos in Vine app;
- Youtube AdAway: Removes Ads in Youtube apps;
- Network Speed Indicator: Displays download speed while device is receiving data;
- ...
We can see that Xposed can provide very helpful features. :)
How Xposed works
Interested in Xposed? Now let's see how it works.
In Android, when init
process is launched, the content in init.rc
will be executed, which will launch /system/bin/app_process
, i.e. the process known as Zygote
process. All Android application processes are forked from the Zygote process. The Zygote process will create the first virtual machine instance, and every time a new application process is forked from Zygote, a new virtual machine instance will also be copied.
Xposed replaced /system/bin/app_process
with a customized one, which loads XposedBridge.jar
, a API library of Xposed, enabling access of classes in XposedBridge.jar
for every application processes. Note that due to the replacement of /system/bin/app_process
file, root permission is required for Xposed framework installation. However, root permission is unnecessary during runtime.
What makes Xposed really powerful is a mechanism that allow developers to replace any methods of any classes, regardless of whether the class is in Android framework or in 3rd party applications. Developers can modify arguments of methods, modify the return value, or totally skip method calls.
Let's see how a method is replaced by Xposed.
In XposedBridge.java
, we can find a private native method named hookMethodNative
, which is implemented in the customized app_process
.
And from below we can see that this method turns the method to be hooked into a native method, then redirects its implementation to a common method named hookedMethodCallback
, so that every time the hooked method is called, it is the hookedMethodCallback
that actually executes without caller knowing.
Then, as shown in below sequence diagram, hookdMethodCallback
will invoke the handleHookedMethod
implemented in XposedBridge.java
, which will then invoke callbacks registered for hooked methods, such as beforeHookedMethod
, afterHookedMethod
. Xposed modules can implement these callbacks to modify arguments or call other methods.
Several ways to track performance of competing Android apps in the past
- Camera capturing: very close to how user experiences, but it's quite time consuming;
- Add Logs in UI Automation scripts: very faulty, it actually measures execution time of automation scripts, nor the application;
- Decompile APK files, modify code and repackage: complex and time consuming, and competitors can update apps in any time;
Analysis performance with Xposed
The most accurate way to calculate page load time is to track start timestamp t1
when page is opened, and track end timestamp t2
when page content is loaded, so t = t2 - t1
will be the load time. With a customized Xposed module, we can inject code to track t1
ad t2
in apps from competitors.
Here are the thoughts:
- Use UI Automator to automatically interacting with 3rd party apps;
- Create a Xposed module, hook several methods, such as methods related to View being clicked;
- Print log in the hooked method to
logcat
, so that we know when page is opened, i.e. thet1
value; - Create a log collector that collect logcat logs during app run;
- Create a log analyzer that calculate performance when app done running, note that if the calculation is done during app run, it might impact app performance;
Create our performance analysis Xposed module
Let's see how to create a Xposed module.
First, we create a class named LoggerModule
which implements IXposedHookLoadPackage
interface. Note that a xposed module will be called every time an application package is loaded, so we need to check package name, in this example, we check if the current running app's package name is equal to com.sankuai.meituan
.
Next, we create a method named hookViewPerformClick
, which hooks performClick
method in android.view.View
and prints a log before the original method is invoked, so that we can get t1
from logcat timestamp.
Then, we need a way to determine page content is loaded. There are several possible ways to do these, in this example, we simply find the method that is called when Network data is fetched.
Now we can activate our Xposed module and reboot.
Running these simple gives the below result:
We can see that a click event occurred at time 39.922, and network data was fetched at time 42.328, then UI got updated. Then with a log analyzer we can export performance data for apps we don't have access to source code.
Conclusion
Developers are capable of resolving many practical problems with Xposed, however, we should picked the hooked method carefully because it actually does have impacts on system performance. In the above example, the performance data will be inaccurate if we hook view's onDraw
method, since it's called very frequently and might slow down apps.