Virtual App对于注解的使用

注解技术在现在非常流行
它是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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值