如何调试Xposed模块不用重启

我想做过Xposed模块开发的一定对调试模块必须要重启手机这个机制不陌生, 拜这个机制所赐每次开发起来苦不堪言。稍微改点东西就需要重启手机少则几十秒要是碰到性能稍差一点的手机几分钟也是有可能的。那我们今天就来好好聊聊怎么才能让修改后的代码即时生效呢?首先要搞清楚这个问题还必须从为什么插件每次修改都要重启手机说起,我们可以通过Xposed开发文档了解到Xposed的工作方式是通过替换/system/bin/app_process这个二进制文件来实现的进程注入的,我们知道app_process是所有进程的启动入口所以xposed替换了这个文件修改了内部执行逻辑优先去加载我们的插件然后再去加载原始的App代码所以才得以实现各种hook,但是问题就出现在加载插件上了,默认的第一次加载插件时系统会在/data/dalvik-cache/创建一份字节码文件给需虚拟机执行,但是因为这个文件只会在第一次加载的时候创建所以当我们修改了插件后再安装这个文件是不会变的,这也就导致我们的改动不会立即生效需要重启手机让系统生成一个新的字节码文件,那肯定有小伙伴会想那我手动把这个字节码文件删了呢?很遗憾我在Android7.0上尝试了一下并未成功原因未知。

好了既然我们知道问题产生的原因那我们就可以找到相应的解决办法,知己知彼百战不殆我们可以在Xposed加载我们插件代码的时候加一层代理用来动态找我们的插件代码位置这样就可以实现不用重启手机即时生效了当然如果仅hook应用了的话还需要强行停止一下应用以确保进程重新加载新代码,如果hook system_server进程了的话那还是需要重启手机的因为需要让system_server进程重新启动加载新的插件代码。

下面是完整的动态加载代码可以直接使用,仅在调试时使用请勿在发布版本中用!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 开发更新模块无需重启 需要在xposed_init指定
*/
public final class HotLoader implements IXposedHookLoadPackage
{

private static final String TAG = HotLoader.class.getSimpleName();
private static final Class<? extends IXposedHookLoadPackage> XPOSED_INIT_CLASS = MainPlugin.class;

@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam)
{
try
{
if(Process.myUid() == Process.SYSTEM_UID)
{
IXposedHookLoadPackage iXposedHookLoadPackage = XPOSED_INIT_CLASS.newInstance();
iXposedHookLoadPackage.handleLoadPackage(lpparam);
}
else
{
PackageInfo packageInfo = getPackageInfo(BuildConfig.APPLICATION_ID, 0, 0);
Log.i(TAG, "hot load dex path:" + packageInfo.applicationInfo.sourceDir + " uid=" + Process.myUid());
PathClassLoader classLoader = new PathClassLoader(packageInfo.applicationInfo.sourceDir, IXposedHookLoadPackage.class.getClassLoader());
IXposedHookLoadPackage iXposedHookLoadPackage = (IXposedHookLoadPackage)classLoader.loadClass(XPOSED_INIT_CLASS.getName()).newInstance();
iXposedHookLoadPackage.handleLoadPackage(lpparam);
}
}
catch(Throwable t)
{
Log.e(TAG, "loader exception", t);
}
}

public static PackageInfo getPackageInfo(String packageName, int flags, int userId) throws Exception
{
@SuppressLint("PrivateApi") Class<?> ServiceManagerClass = Class.forName("android.os.ServiceManager");
IBinder binder = (IBinder)XposedHelpers.callStaticMethod(ServiceManagerClass, "checkService", "package");
@SuppressLint("PrivateApi") Class<?> IPackageManager$StubClass = Class.forName("android.content.pm.IPackageManager$Stub");
IInterface packageServiceManager = (IInterface)XposedHelpers.callStaticMethod(IPackageManager$StubClass, "asInterface", binder);
return (PackageInfo)XposedHelpers.callMethod(packageServiceManager, "getPackageInfo", packageName, flags, userId);
}

}
Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2015-2024 Kaisar
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信