参考:,我的Xposed之路就是这位大神引导的啊;
在读这篇文章之前请务必仔细阅读这篇博文才能更好的明白接下来的内容;
Xposed源码:,真是大神级别的啊;
下面这段概述从上面所说博文中摘录引用的:
Xposed是GitHUB上rovo89大大设计的一个针对Android平台的动态劫持项目,通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持。与采取传统的Inhook方式(详见Dynamic Dalvik Instrumentation分析这篇本章 )相比,Xposed在开机的时候完成对所有的Hook Function的劫持,在原Function执行的前后加上自定义代码。
Xposed框架的基本运行环境如下:
|
Configuration
|
RequireMent
|
|
Root Access
|
因为Xposed工作原理是在/system/bin目录下替换文件,在install的时候需要root权限,但是运行时不需要root权限。
|
|
版本要求
|
需要在Android 4.0以上版本的机器中
|
如果你要先体验Xposed的强大,可以先安装Xprivacy,它是基于Xposed框架实现的权限管理App;你就可以感受到Xposed的强大了;
那么下面就来看看Xposed如何才能使用呢?
要安装Xposed框架,必须先安装一个Xposed Installer的application;就是一个Xposed安装管理器了;打开后会提示用户如上图左一的红色字提示部分;进去以后点击“安装/更新”按钮,成功后会如上图右一提示的那样,重启以后,Xposed框架就已经安装成功了;
在分析安装过程之前先看一下Xposed Installer的包结构;
- app_process*文件:用来替换系统app_process的;
- Xposed-Disabler-Recovery.zip/Xposed-Installer-Recovery.zip:应该是和recovery相关,暂未了解;
- XposedBridge.jar:XposedBridge.jar:Xposed提供的jar文件,负责在Native层与FrameWork层进行交互。
- libsuperuser-185868.jar:how to SU,https:
- StickyListHeaders-d7f6fc.jar:listView效果,https:
- tools:签名工具包
接下面我就来分析下这个安装过程;
首先肯定得找到 “安装/更新” 这个Button的onClick事件了;
- XposedInstaller/src/de/robv/android/xposed/installer/InstallerFragement.java
-
- btnInstall.setOnClickListener(new AsyncClickListener(btnInstall.getText()) {
- @Override
- public void onAsyncClick(View v) {
- final boolean success = install();
- getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
-
- Log.e("xposed", "Install/Update button clicked!!!");
-
- refreshVersions();
- if (success)
- ModuleUtil.getInstance().updateModulesList(false);
-
-
-
-
- XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, appProcessInstalledVersion).commit();
-
- getView().findViewById(R.id.install_reverted_warning).setVisibility(View.GONE);
- }
- });
- }
- });
自定义的AsyncClickListener就不看了,主要好像是加了一个进度条的处理过程;,直接看重要逻辑;
主要逻辑都在:
- final boolean success = install();
看看install方法,这个方法很长;
- de.robv.android.xposed.installer.InstallerFragement.java
- private boolean install() {
- final int installMode = getInstallMode();
-
- if (!startShell())<span style="white-space:pre">
- return false;
- <span style="white-space:pre"> </span>
- List<String> messages = new LinkedList<String>();
- boolean showAlert = true;
- try {
- messages.add(getString(R.string.sdcard_location, XposedApp.getInstance().getExternalFilesDir(null)));
- messages.add("");
-
- messages.add(getString(R.string.file_copying, "Xposed-Disabler-Recovery.zip"));
- if (AssetUtil.writeAssetToSdcardFile("Xposed-Disabler-Recovery.zip", 00644) == null) {
- messages.add("");
- messages.add(getString(R.string.file_extract_failed, "Xposed-Disabler-Recovery.zip"));
- return false;
- }
-
- File appProcessFile = AssetUtil.writeAssetToFile(APP_PROCESS_NAME, new File(XposedApp.BASE_DIR + "bin/app_process"), 00700);
- if (appProcessFile == null) {
- showAlert(getString(R.string.file_extract_failed, "app_process"));
- return false;
- }
-
- if (installMode == INSTALL_MODE_NORMAL) {
-
- messages.add(getString(R.string.file_mounting_writable, "/system"));
- if (mRootUtil.executeWithBusybox("mount -o remount,rw /system", messages) != 0) {
- messages.add(getString(R.string.file_mount_writable_failed, "/system"));
- messages.add(getString(R.string.file_trying_to_continue));
- }
-
- if (new File("/system/bin/app_process.orig").exists()) {
- messages.add(getString(R.string.file_backup_already_exists, "/system/bin/app_process.orig"));
- } else {
- if (mRootUtil.executeWithBusybox("cp -a /system/bin/app_process /system/bin/app_process.orig", messages) != 0) {
- messages.add("");
- messages.add(getString(R.string.file_backup_failed, "/system/bin/app_process"));
- return false;
- } else {
- messages.add(getString(R.string.file_backup_successful, "/system/bin/app_process.orig"));
- }
-
- mRootUtil.executeWithBusybox("sync", messages);
- }
-
- messages.add(getString(R.string.file_copying, "app_process"));
- if (mRootUtil.executeWithBusybox("cp -a " + appProcessFile.getAbsolutePath() + " /system/bin/app_process", messages) != 0) {
- messages.add("");
- messages.add(getString(R.string.file_copy_failed, "app_process", "/system/bin"));
- return false;
- }
- if (mRootUtil.executeWithBusybox("chmod 755 /system/bin/app_process", messages) != 0) {
- messages.add("");
- messages.add(getString(R.string.file_set_perms_failed, "/system/bin/app_process"));
- return false;
- }
- if (mRootUtil.executeWithBusybox("chown root:shell /system/bin/app_process", messages) != 0) {
- messages.add("");
- messages.add(getString(R.string.file_set_owner_failed, "/system/bin/app_process"));
- return false;
- }
-
- } else if (installMode == INSTALL_MODE_RECOVERY_AUTO) {
- if (!prepareAutoFlash(messages, "Xposed-Installer-Recovery.zip"))
- return false;
-
- } else if (installMode == INSTALL_MODE_RECOVERY_MANUAL) {
- if (!prepareManualFlash(messages, "Xposed-Installer-Recovery.zip"))
- return false;
- }
-
- File blocker = new File(XposedApp.BASE_DIR + "conf/disabled");
- if (blocker.exists()) {
- messages.add(getString(R.string.file_removing, blocker.getAbsolutePath()));
- if (mRootUtil.executeWithBusybox("rm " + blocker.getAbsolutePath(), messages) != 0) {
- messages.add("");
- messages.add(getString(R.string.file_remove_failed, blocker.getAbsolutePath()));
- return false;
- }
- }
-
- messages.add(getString(R.string.file_copying, "XposedBridge.jar"));
- File jarFile = AssetUtil.writeAssetToFile("XposedBridge.jar", new File(JAR_PATH_NEWVERSION), 00644);
- if (jarFile == null) {
- messages.add("");
- messages.add(getString(R.string.file_extract_failed, "XposedBridge.jar"));
- return false;
- }
-
- mRootUtil.executeWithBusybox("sync", messages);
-
- showAlert = false;
- messages.add("");
- if (installMode == INSTALL_MODE_NORMAL)
- offerReboot(messages);
- else
- offerRebootToRecovery(messages, "Xposed-Installer-Recovery.zip", installMode);
-
- return true;
-
- } finally {
- AssetUtil.removeBusybox();
-
- if (showAlert)
- showAlert(TextUtils.join("\n", messages).trim());
- }
- }
Step1:
- getInstallMode()正常安装情况返回的mode为:INSTALL_MODE_NORMAL
Step2:
startShell()方法主要是启动一个用来和root交互的shell进程;
-
-
-
-
-
-
- public synchronized boolean startShell() {
- if (mShell != null) {
- if (mShell.isRunning())<span style="white-space:pre"> </span>
- return true;
- else
- dispose();
- }
-
- mCallbackThread = new HandlerThread("su callback listener");
- mCallbackThread.start();
-
- mCommandRunning = true;
- mShell = new Shell.Builder()<span style="white-space:pre"> </span>
- .useSU()<span style="white-space:pre"> </span>
- .setHandler(new Handler(mCallbackThread.getLooper()))<span style="white-space:pre"> </span>
- .setWantSTDERR(true)<span style="white-space:pre"> </span>
- .setWatchdogTimeout(10)<span style="white-space:pre"> </span>
- .open(commandResultListener);<span style="white-space:pre"> </span>
-
- waitForCommandFinished();
-
- if (mLastExitCode != OnCommandResultListener.SHELL_RUNNING) {
- dispose();
- return false;
- }
-
- return true;
- }
这个Shell类位于libsuperuser.jar中,主要是用来提供一个可以在root下的shell中执行命令的功能类;
Step3:
- 在接下来的Step3的整个执行过程是:
- 1、AssetUtil.writeAssetToSdcardFile("Xposed-Disabler-Recovery.zip", 00644)
- 2、AssetUtil.writeAssetToFile(APP_PROCESS_NAME, new File(XposedApp.BASE_DIR + "bin/app_process"), 00700)
- 3、mRootUtil.executeWithBusybox("mount -o remount,rw /system", messages)
- 4、mRootUtil.executeWithBusybox("cp -a /system/bin/app_process /system/bin/app_process.orig", messages)
- 5、mRootUtil.executeWithBusybox("sync", messages);执行sync
- 6、mRootUtil.executeWithBusybox("cp -a " + appProcessFile.getAbsolutePath() + " /system/bin/app_process", messages)
- 7、mRootUtil.executeWithBusybox("chmod 755 /system/bin/app_process", messages)
- 8、mRootUtil.executeWithBusybox("chown root:shell /system/bin/app_process", messages)
- 9、mRootUtil.executeWithBusybox("rm " + blocker.getAbsolutePath(), messages)
- 10、AssetUtil.writeAssetToFile("XposedBridge.jar", new File(JAR_PATH_NEWVERSION), 00644)
- 11、mRootUtil.executeWithBusybox("sync", messages)
- 12、mRootUtil.executeWithBusybox("reboot", messages)
这样,整个框架的安装过程就完成了;
|