Virtual App对于注解的使用
来源:互联网 发布:网络语233333什么意思 编辑:程序博客网 时间:2024/05/16 11:51
注解技术在现在非常流行
它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
注解的基本知识网上很多,在va中也大量使用了注解技术,体现了代码分析和编译检查的特征。对于我们理解注解有很大的帮助。
编译检查
在va中部分mirror类使用了注解,如IAppOpsService
public class IAppOpsService { public static Class<?> TYPE = RefClass.load(IAppOpsService.class, "com.android.internal.app.IAppOpsService"); public static class Stub { public static Class<?> TYPE = RefClass.load(Stub.class, "com.android.internal.app.IAppOpsService$Stub"); @MethodParams({IBinder.class}) public static RefStaticMethod<IInterface> asInterface; }}
@MethodParams注解范围是字段。注解如下
@Target({ElementType.FIELD})\\注解字段@Retention(RetentionPolicy.RUNTIME)public @interface MethodParams { Class<?>[] value();}
RefStaticMethod里承担了对注解的检查,只有当注解类型与实际类型一致时,我们才去尝试加载类并且获取该方法。这里的注解实际上就是对我们要反射的方法进行了检查,只有当我们注解元IBinder.class与实际赋值的Class一致时才会去尝试获取该method。MethodReflectParams与之类似,只是对于方法的检查更为复杂。
if (field.isAnnotationPresent(MethodParams.class)) { //获取注解Class Class<?>[] types = field.getAnnotation(MethodParams.class).value(); for (int i = 0; i < types.length; i++) { Class<?> clazz = types[i]; if (clazz.getClassLoader() == getClass().getClassLoader()) { try { Class.forName(clazz.getName()); Class<?> realClass = (Class<?>) clazz.getField("TYPE").get(null); types[i] = realClass; } catch (Throwable e) { throw new RuntimeException(e); } } } this.method = cls.getDeclaredMethod(field.getName(), types); this.method.setAccessible(true); }
这里其实就是实现了代码检查,如果没有使用注解进行检查,代码会直接尝试获取方法
for (Method method : cls.getDeclaredMethods()) { if (method.getName().equals(field.getName())) { this.method = method; this.method.setAccessible(true); break;
代码分析
在比较早的va中 ,以ActivityManagerPatch为例
@Patch({StartActivity.class, StartActivityAsCaller.class, StartActivityAndWait.class, StartActivityWithConfig.class, StartActivityIntentSender.class, StartNextMatchingActivity.class, StartVoiceActivity.class, GetIntentSender.class, RegisterReceiver.class, GetContentProvider.class, GetContentProviderExternal.class,StartActivities.class, GetActivityClassForToken.class, GetTasks.class, GetRunningAppProcesses.class, StartService.class, StopService.class, StopServiceToken.class, BindService.class, UnbindService.class, PeekService.class, ServiceDoneExecuting.class, UnbindFinished.class, PublishService.class, HandleIncomingUser.class, SetServiceForeground.class, BroadcastIntent.class, GetCallingPackage.class, GrantUriPermissionFromOwner.class, CheckGrantUriPermission.class, GetPersistedUriPermissions.class, KillApplicationProcess.class, ForceStopPackage.class, AddPackageDependency.class, UpdateDeviceOwner.class, CrashApplication.class, GetPackageForToken.class, GetPackageForIntentSender.class, SetPackageAskScreenCompat.class, GetPackageAskScreenCompat.class, CheckPermission.class, PublishContentProviders.class, GetCurrentUser.class, UnstableProviderDied.class, GetCallingActivity.class, FinishActivity.class, GetServices.class, KillBackgroundProcesses.class,KillBackgroundProcessesWithCaller.class, SetTaskDescription.class,})
每个元素都是一个独立的代理类,对注解元素进行解析
Class<? extends PatchDelegate> clazz = getClass();//获取注解 Patch patch = clazz.getAnnotation(Patch.class); int version = Build.VERSION.SDK_INT;//对注解进行解析 if (patch != null) { Class<?>[] hookTypes = patch.value(); for (Class<?> hookType : hookTypes) { ApiLimit apiLimit = hookType.getAnnotation(ApiLimit.class); boolean needToAddHook = true; if (apiLimit != null) { int apiStart = apiLimit.start(); int apiEnd = apiLimit.end(); boolean highThanStart = apiStart == -1 || version > apiStart; boolean lowThanEnd = apiEnd == -1 || version < apiEnd; if (!highThanStart || !lowThanEnd) { needToAddHook = false; } }//添加到hook方法中 if (needToAddHook) { addHook(hookType); }
va对代码进行了重构 ,将独立的hook方法聚合在了一起,每一个hook方法都是注解类的内部类
class MethodProxies { static class ForceStopPackage extends MethodProxy { @Override public String getMethodName() { return "forceStopPackage"; } @Override public Object call(Object who, Method method, Object... args) throws Throwable { String pkg = (String) args[0]; int userId = VUserHandle.myUserId(); VActivityManager.get().killAppByPkg(pkg, userId); return 0; } @Override public boolean isEnable() { return isAppProcess(); } } ...
对于注解的解析基本类似
Class<? extends MethodInvocationProxy> clazz = getClass(); Inject inject = clazz.getAnnotation(Inject.class); if (inject != null) { Class<?> proxiesClass = inject.value(); //获取内部类 Class<?>[] innerClasses = proxiesClass.getDeclaredClasses(); for (Class<?> innerClass : innerClasses) { if (!Modifier.isAbstract(innerClass.getModifiers()) && MethodProxy.class.isAssignableFrom(innerClass) && innerClass.getAnnotation(SkipInject.class) == null) { addMethodProxy(innerClass); } } }
重构之后增加了代码的可读性,所有对于activitymanager的代理操作都写在了一个类当中,我们无论是想要添加新的hook方法或者修改hook方法都可以很快速的实现。
注解我认为这是一种高级技巧,主要是为了增加可读性,降低代码重复编写。
参考资料:
http://blog.csdn.net/u010039929/article/details/77745319
http://blog.csdn.net/ztchun/article/details/59637212
- Virtual App对于注解的使用
- DJunit对于Virtual Mock的支持
- 对于java注解的认识
- 对于好书APP的总结
- virtual/override的使用
- Virtual的使用
- virtual destructor的使用
- virtual关键字的使用
- IBM对于IT的新注解
- 对于注解的浅薄理解,有待修正
- 对于cookie的使用
- 对于多线程的使用
- 对于默认值的使用
- 对于虚拟机的使用
- 对于Toast的使用
- 对于模态框的使用
- 对于移动端 APP,虚拟机注册或使用的作弊行为有何应对良策
- FragmentPagerAdapter对于app.Fragment的兼容
- 代码1 爬取 百度logo(图片)
- 欢迎使用CSDN-markdown编辑器
- C++中struct和class的区别
- android studio 跳出方框提示快捷键如何取消
- 网站前台和后台可以同时登录
- Virtual App对于注解的使用
- 代码2 代替浏览器行为爬取数据
- 63.设计模式笔记-单例模式
- 制作补丁
- nginx在linux下的安装
- 关于spring的配置注入和注释注入的见解
- Linux 系统便捷安装pycharm
- iOS UIFont原生字体和第三方字体.ttf的使用
- JavaScript类型浅谈