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