xposed开发之清除应用数据(研究历程)

    最近在研究xposed,有个需求要作到清除其余应用数据,xposed功能足够强大,应该能够实现这个功能,下面是基于android4.4.4研究的思路。java

    google只能开放了清楚缓存的API,清除数据的API隐藏了,而调用清理数据的方法在“设置”中的“应用”里,找到设置功能的源码,代码位置 com.android.settings.applications.InstalledAppDetails ,点击事件在这linux

调用了initiateClearUserData,看看这里面怎么实现的android

调用了ActivityManager的clearApplicationUserData,参数是该应用的包名和一个ClearUserDataObserver的实例缓存

IPackageDataObserver是有AIDL生成的,位于android.content.pm包内,咱们能够新建一个相同的包名,把AIDL放在这里。app

注:有些应用详情里该按钮不是清除数据,是管理空间,清除数据的按钮在应用自定义的界面里,可是最终实现清除数据仍是调用的clearApplicationUserDatasocket

clearApplicationUserData是隐藏方法,直接调用了ActivityManagerNative的方法ide

ActivityManagerNative:学习

这里直接使用反射或者Xposed的callmethod调用这两个方法都会报错,缺乏权限ui

android.permission.CLEAR_APP_USER_DATA

这里并无实现具体的方法,真正的实如今ActivityManagerService中,参考http://www.jianshu.com/p/18517a4ef8e1google

ActivityManagerService:

该方法上面部分是获取pid、uid,给IPackageManager的对象赋值和权限检测,下面执行清除数据。最开始的思路是直接hook AppGlobals.getPackageManager()的clearApplicationUserData,可是仍旧报缺乏权限错误。。。继续分析:

AppGlobals:

ActivityThread:

到这里遇到IPackageManager.aidl生成的Stub类,PackageManagerService继承了IPackageManager.Stub

PackageManagerService:

又是权限检测,跳过,进入clearApplicationUserDataLI

int retCode = mInstaller.clearUserData(packageName, userId);

进入Installer方法

该类大概是建立本地socket,执行linux命令行,进行各类应用的安装、移动、卸载、清除数据等

可是hook此方法,仍旧报错,空指针异常,并且hook connect也链接不上

Class installCls = XposedHelpers.findClass("com.android.server.pm.Installer",lpp.classLoader);
Object installObj = XposedHelpers.newInstance(installCls);
boolean lean = (boolean) XposedHelpers.callMethod(installObj,"ping");
boolean bo = (boolean) XposedHelpers.callMethod(installObj,"connect");
XposedBridge.log("lean:"+lean+"--bo:"+bo);

实例化Installer出的问题.查了资料,Installer在系统启动时由其余类调用,启动完成后用findAndHookMethod没法hook到。因而实现Xposed另外一接口XposedHookZygoteInit 

@Override
public void initZygote(StartupParam startupParam) throws Throwable {
    Class installCls = XposedHelpers.findClass("com.android.server.pm.Installer",null);
    XposedHelpers.findAndHookMethod(installCls, "writeCommand",String.class, new XC_MethodHook() {
        @Override
        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
            String string = (String) param.args[0];
            XposedBridge.log("string:"+string);
            if(string.contains("com.google.android.gms"))
                param.args[0] = "rmuserdata com.google.android.gms 0";
        }

    });

}

以google play service为例,这种状况下能够清除此app的数据。可是这种方法不可控,必须放在initZygote中,并且Installer不能经过反射实例化,只能另想办法。

    郁闷两天后,想到既然从ActivityManager、PackageManagerService等类中不能调用是由于权限限制,那就hook检测权限的方法,让个人应用经过权限检测。最开始打算之外部调用的方式(在非Xposed中,例如activity,以反射的方式调用清除数据的方法,Xposed hook权限检测方法)从 ActivityManagerService入手,由于PackageManagerService的构造方法须要传多个参数,包括Installer的对象。ActivityManagerService里检测权限的是checkComponentPermission方法,可是经过反射获取ActivityManagerService对象时又报错,FileNotFoundException,引起异常的位置是mBatteryStatsService = new BatteryStatsService(new File( systemDir, "batterystats.bin").toString());

batterystats.bin文件位于/data/system/下,但即便我得到了root权限依然触发异常,不知道什么缘由。这样只能在handleLoadPackage中调用清除数据,在Xposed外部设置个合适方法触发清理数据,好比得到IMEI、杀掉某个进程等,经过hook这些方法,而后调用清除数据的方法:

XposedHelpers.findAndHookMethod("android.app.ActivityManager", lpp.classLoader, "killBackgroundProcesses",String.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                String process = (String) param.args[0];
                XposedBridge.log("process:"+process);
                if("com.google.android.gsf".equals(process)){
                    ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
                    XposedHelpers.callMethod(manager,"clearApplicationUserData",packageName,clearDataUserData);

                }

            }
        });

这是以杀死com.google.android.gsf为例。

    权限检测这里有两部分,就是ActivityManagerService 的checkComponentPermission了:

XposedHelpers.findAndHookMethod("com.android.server.am.ActivityManagerService", lpp.classLoader, "checkComponentPermission", String.class, int.class, int.class, int.class, boolean.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                if(Manifest.permission.CLEAR_APP_USER_DATA.equals(param.args[0])) {
                    int re = (int) param.getResult();
                    XposedBridge.log("ActivityManagerService re:"+re);
                    param.setResult(0);//PackageManager.PERMISSION_GRANTED

                }
            }
        });

    总结:最终实现的方法很简单,可是过程分析花费的时间很长,一方面源于对源码的不了解,好比AIDL原理,系统启动的顺序等等。好在源码结构好,容易看懂,否则还没分析完就歇菜放弃了。这里主要是为学习作个笔记,清除其余应用的数据是很危险的行为,必定要慎用!慎用

相关文章
相关标签/搜索