研究Xposed相关一:Xposed框架的安装

说到Xposed,首先得了解Xposed是什么;

参考:http://blog.csdn.net/wxyyxc1992/article/details/17320911,我的Xposed之路就是这位大神引导的啊;

在读这篇文章之前请务必仔细阅读这篇博文才能更好的明白接下来的内容;


Xposed源码:https://github.com/rovo89,真是大神级别的啊;


下面这段概述从上面所说博文中摘录引用的:

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://github.com/Chainfire/libsuperuser
StickyListHeaders-d7f6fc.jar:listView效果,https://github.com/emilsjolander/StickyListHeaders
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);//更新APP目录下的的modules.list,此文件用来记录使用了Xposed框架的module,比如XPrivacy就是一种

							// Start tracking the last seen version, irrespective of the installation method and the outcome.
							// 0 or a stale version might be registered, if a recovery installation was requested
							// It will get up to date when the last seen version is updated on a later panel startup
							XposedApp.getPreferences().edit().putInt(PREF_LAST_SEEN_BINARY, appProcessInstalledVersion).commit();
							// Dismiss any warning already being displayed
							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(); //Step1

		if (!startShell())<span style="white-space:pre">	//Step2
			return false;
<span style="white-space:pre">		</span>//Step3
		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) {
				// Normal installation
				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进程;

/**
	 * Starts an interactive shell with root permissions.
	 * Does nothing if already running.
	 *
	 * @return true if root access is available, false otherwise
	 */
	public synchronized boolean startShell() {
		if (mShell != null) {
			if (mShell.isRunning())<span style="white-space:pre">	</span>//判断当前shell进程是否运行
				return true;
			else
				dispose();
		}

		mCallbackThread = new HandlerThread("su callback listener");
		mCallbackThread.start();

		mCommandRunning = true;
		mShell = new Shell.Builder()<span style="white-space:pre">	</span>//可以在root下执行命令的shell
			.useSU()<span style="white-space:pre">	</span>//Su
			.setHandler(new Handler(mCallbackThread.getLooper()))<span style="white-space:pre">	</span>//设置一个callback HandlerThread
			.setWantSTDERR(true)<span style="white-space:pre">	</span>//是否输出错误结果
			.setWatchdogTimeout(10)<span style="white-space:pre">	</span>//命令执行超时时间设置
			.open(commandResultListener);<span style="white-space:pre">	</span>//启动shell进程,并且设置result监听

		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)//将asserts中的Xposed-Disabler-Recovery.zip拷贝到/sdcard下;
2、AssetUtil.writeAssetToFile(APP_PROCESS_NAME, new File(XposedApp.BASE_DIR + "bin/app_process"), 00700)//将asserts下的arm/x86包中的app_process_*文件拷贝到APP目录下的bin中,并命名为app_process
3、mRootUtil.executeWithBusybox("mount -o remount,rw /system", messages)//利用busybox执行将/system目录重新挂载为可读写
4、mRootUtil.executeWithBusybox("cp -a /system/bin/app_process /system/bin/app_process.orig", messages)//将/system/bin/app_process重命名为system/bin/app_process.orig
5、mRootUtil.executeWithBusybox("sync", messages);执行sync
6、mRootUtil.executeWithBusybox("cp -a " + appProcessFile.getAbsolutePath() + " /system/bin/app_process", messages)//将APP目录下的app_process拷贝到/system/bin目录下;这样就替换了系统的app_process
7、mRootUtil.executeWithBusybox("chmod 755 /system/bin/app_process", messages)//更改app_process权限为755
8、mRootUtil.executeWithBusybox("chown root:shell /system/bin/app_process", messages)//更改app_process own为root和shell
9、mRootUtil.executeWithBusybox("rm " + blocker.getAbsolutePath(), messages)//删除APP目录下conf/disabled文件,如果此文件存在
10、AssetUtil.writeAssetToFile("XposedBridge.jar", new File(JAR_PATH_NEWVERSION), 00644)//将asserts目录下的XposedBridge.jar复制到APP目录下的bin目录,并重命名为XposedBridge.jar.newversion
11、mRootUtil.executeWithBusybox("sync", messages)//执行sync
12、mRootUtil.executeWithBusybox("reboot", messages)//弹出重启的提示框,点击重启手机


这样,整个框架的安装过程就完成了;



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值