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

原创粉丝点击