IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]Android中实现Activity的启动拦截之----实现360卫士的安装应用界面

    jiangwei0910410003发表于 2015-09-29 17:47:35
    love 0

    第一、摘要

    今天不是周末,但是我已经放假了,所以就开始我们的技术探索之旅,今天我们来讲一下Android中最期待的技术,就是拦截Activity的启动,其实我在去年的时候,就像实现这个技术了,但是因为知识不充足,就放弃了,当时的需求很简单,就是实现应用锁,就是给每个应用打开的时候加上密码,不了解的同学,可以看看这篇文章:

    http://blog.csdn.net/jiangwei0910410003/article/details/42149975

    不过,当时也是实现了,只是使用了监听TopActivity的方式实现的,后台起一个Service来轮询监听。但是当时想到了性能上的问题,因为感觉后台启动一个Service来进行轮询操作会很消耗性能,但是最后发现,现在市场上的应用锁应用实现的原理都是这么做的,所以当时就是用这个技术来做了。但是关于其他方式来做的工作没有断续,现在有时间就来研究一下如何通过拦截Activity的启动方式来实现拦截。因为:监听比轮训机制高效。


    第二、前提准备

    不过实现了拦截Activity启动技术实现之后,我们还会发现这个技术在很多地方都会用到。关于注入技术需要关注的文章:

    http://blog.csdn.net/jiangwei0910410003/article/details/40949475

    看完这篇文章,才能理解注入技术,才能看懂这篇文章。看完这篇文章之后,我们能看到三个文件:

    poison; libproxybinder.so; DemoInject3.apk

    关于这三个文件的作用就不多说了。看完文章就知道了。


    第三、技术解析

    涉及到源码类:

    ContextImpl.java

    ActivityThread.java

    Instrumentation.java

    ActivityManagerNative.java

    那么这里我们现在需要拦截Activity的启动流程的话,那就要看看Activity的启动源代码:

    先来看一下ContextImpl.java中的startActivity代码:


    它内部是调用ActivityThread类的Instrumentation变量的execStartActivity方法:


    它内部是调用ActivityManagerNative的startActivity方法的:


    到这里我们可以看到了,这里使用了Binder机制来做的,我们知道

    ActivityManager

    IActivityManager

    ActivityManagerNative

    ActivityManagerService

    ActivityManagerProxy

    这几个类的关系:


    关于他们之间的具体信息,这里就不做详细介绍了。


    我们看到ActivityManagerNative.java中的代码之后,我们知道我们只需要拦截code为启动Activity的就可以了:START_ACTIVITY_TRANSACTION

    当然我们还需要解析Parcel数据,才能得到启动Activity的信息:具体的Parcel数据格式我们在代码中也能看到:

    data.enforceInterface(IActivityManager.descriptor);
    IBinder b = data.readStrongBinder();
    IApplicationThread app = ApplicationThreadNative.asInterface(b);
    String callingPackage = data.readString();
    Intent intent = Intent.CREATOR.createFromParcel(data);
    String resolvedType = data.readString();
    IBinder resultTo = data.readStrongBinder();
    String resultWho = data.readString();
    int requestCode = data.readInt();
    int startFlags = data.readInt();
    ProfilerInfo profilerInfo = data.readInt() != 0
    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
    Bundle options = data.readInt() != 0
    ? Bundle.CREATOR.createFromParcel(data) : null;
    int result = startActivity(app, callingPackage, intent, resolvedType,
    		resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
    reply.writeNoException();
    reply.writeInt(result);


    拦截的code和Parcel的数据结构我们都知道了。那么我们来看一下DemoInject3项目的核心代码:

    EntryClass.java

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    
    	/**
    	 *  data.enforceInterface(IActivityManager.descriptor);
    	            IBinder b = data.readStrongBinder();
    	            IApplicationThread app = ApplicationThreadNative.asInterface(b);
    	            String callingPackage = data.readString();
    	            Intent intent = Intent.CREATOR.createFromParcel(data);
    	            String resolvedType = data.readString();
    	            IBinder resultTo = data.readStrongBinder();
    	            String resultWho = data.readString();
    	            int requestCode = data.readInt();
    	            int startFlags = data.readInt();
    	            ProfilerInfo profilerInfo = data.readInt() != 0
    	                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
    	            Bundle options = data.readInt() != 0
    	                    ? Bundle.CREATOR.createFromParcel(data) : null;
    	            int result = startActivity(app, callingPackage, intent, resolvedType,
    	                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
    	            reply.writeNoException();
    	            reply.writeInt(result);
    	 */
    
    	if(code == 3){
    		try{
    			Log.i("TTT", "code:"+code);
    			data.enforceInterface("android.app.IActivityManager");
    			IBinder b = data.readStrongBinder();
    			Log.i("TTT", "binder:"+b.getInterfaceDescriptor());
    			String callingPackage = data.readString();
    			Log.i("TTT","pkg:"+callingPackage);
    			Intent intent = Intent.CREATOR.createFromParcel(data);
    			Log.i("TTT", "intent:"+intent);
    			if(intent != null){
    				Log.i("TTT", "data:"+intent.getData());
    				Log.i("TTT", "type:"+intent.getType());
    			}
    			String resolvedType = data.readString();
    			Log.i("TTT", "resolvedType:"+resolvedType);
    		}catch(Exception e){
    			Log.i("TTT", "error:"+Log.getStackTraceString(e));
    		}
    	}
    
    	return mBinder.transact(code, data, reply, flags);
    }


    DemoInject3项目的下载地址:http://download.csdn.net/detail/jiangwei0910410003/9147665


    第四、运行程序

    我们得到上面的三个文件:

    poison; libproxybinder.so; DemoInject3.apk

    下载地址:http://download.csdn.net/detail/jiangwei0910410003/9147671


    将poison和libproxybinder.so两个文件放到data/data目录下

    adb push poison /data/data

    adb push libproxybinder.so /data/data

    将DemoInject3.apk存放到/data/local/tmp目录下

    adb push DemoInject3.apk /data/local/tmp


    运行:

    先找到system_server的进程id,然后注入

    然后到/data/data/目录下

    运行poison



    这时候我们使用  adb logcat -s TTT  查看log:


    注入成功,那么这时候我们打开几个App看看log:


    看到log之后,我们可以看到我们的拦截成功了,我们可以得到启动Activity的Intent内容和App的包名信息等。

    多么激动的一天,拦截成功之后,我们什么事都可以干了。这个实现应用锁的效率会高很多的。但是这个也是有一个弊端,需要root。


    第五、拦截系统安装界面,实现自己的安装界面

    那么这个技术除了实现应用锁,还有其他什么用途呢?

    下面我们来看一下360卫士的自定义安装界面的实现,先来看看他的效果:


    我们看到他能够替换系统的安装界面,自己定义的安装界面。那么我们现在也是可以实现的。我们现在打开一个apk安装:


    这里我们可以看到Intent中携带的信息,和type类型,pkg是安装来源的App的包名,Intent中有待安装的apk路径,有了路径之后,我们就可以得到这个apk的信息。那么这个安装界面的实现就不难了。

    当然这个问题困扰了我很长时间,也是这个问题驱使我义无反顾的来解决这个问题。360的技术很不了的。一个360卫士的Apk我们学到的东西很多,而且可能学不完。后面我还有一篇文章专门来解读360手机卫士的技术点实现。


    第六、总结

    今天就介绍了如何通过注入技术来实现拦截Activity的启动,这个技术的实现,能够解决我们很多问题,当然这个注入技术是需要root的,所以这里只是理论介绍他可以来实现应用锁。但是我们在实际项目中,不会采用这个技术的,原因很简单,root是一个可以研究的技术,但是本人坚决反对使用这个技术来开发产品,因为这个技术是和Google开发者相违背的。这么做是不正确的。当然只是个人观点。不过后面我还会介绍一种技术来实现应用锁技术:辅助功能(AccessibilityService)。


    PS: 关注微信,最新Android技术实时推送


















沪ICP备19023445号-2号
友情链接