以下几篇文章是较深入分析binder机制。
目录
1. Android - Binder机制 - ServiceManager
2. Android - Binder机制 - 普通service注册
3. Android - Binder机制 - 获得普通service
4. Android - Binder机制 - client和普通service交互
5. Android - Binder机制 - Binder框架总结
6. Android - Binder机制 - ProcessState和IPCThreadState
7. Android - Binder机制 - 驱动
和前两篇结构基本一致,只说明特别的几个地方:
1. Camera客户端执行startPreview()是通过BpCamera来完成的;
2. ICamera定义了摄像头操作的接口,它是抽象类,BpCamera是客户端的实现;
3. CameraService: :Client是服务端,每个Camera客户端对应一个CameraService: :Client;
4. BnCamera服务端对ICamera的实现;
5. BBinder在之前没见过,它服务端对IBinder的实现,主要接口是onTransact();
6. 这个图BpBinder和BBinder应该各对应一组ProcessState和IPCThreadState,因为它们存在于每个binder进程,不管是客户端还是服务端;
1. Camera的startPreview()调用BpCamera的startPreview();
2. BpCamera执行remote()->transact(START_PREVIEW, data, &reply),而remote()就是BpBinder;
3. BpBinder里的mHandle是CameraService::Client的handle索引;
4. Camera进程的IPCThreadState的transact转发请求;
5. 服务端的IPCThreadState通过talkWithDriver接收到上面的请求,当然这其中mHandle起到了很重要的作用;
6. BBinder的transact和onTransact和BnCamera的onTransact依次执行;
7. BnCamera的onTransact中调用了startPreview()函数,而这个函数就是CameraService::Client的startPreview();
8. 返回值按照相反的路径返回;
一、知识点
在编写AspectJ aspect时,可以直接在通知注解中嵌入切入点表达式。但是,相同的切入点表达式可能在多个通知中重复。
和其它许多AOP实现一样,AspectJ也允许独立地定义切入点,在多个通知中重用。
二、代码示例
在AspectJ aspect中,切入点可以声明为一个带有@Pointcut注解的简单方法。切入点的方法体通常为空,因为将切入点定义与应用程序逻辑混合在一起是不合理的。切入点方法的访问修饰符控制切入点的可见性。其他通知可以用方法名称引用这个切入点。
package com.codeproject.jackie.springrecipesnote.springaop;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author jackie
*
*/
@Aspect
public class CalculatorLoggingAspect {
private Log log = LogFactory.getLog(this.getClass());
@Pointcut("execution(* *.*(..))")
private void loggingOperation() {
}
@Before("loggingOperation()")
public void logBefore(JoinPoint joinPoint) {
log.info("The method " + joinPoint.getSignature().getName()
+ "() begins with " + Arrays.toString(joinPoint.getArgs()));
}
@After("loggingOperation()")
public void logAfter(JoinPoint joinPoint) {
log.info("The method " + joinPoint.getSignature().getName() + "() ends");
}
@AfterReturning(pointcut = "loggingOperation())", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
}
@AfterThrowing(pointcut = "loggingOperation())", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
log.error("An exception " + e + " has been thrown in " + joinPoint.getSignature().getName() + "()");
}
@Around("loggingOperation()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("The method " + joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs()));
try {
Object result = joinPoint.proceed();
log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument " + Arrays.toString(joinPoint.getArgs()) + " in " + joinPoint.getSignature().getName() + "()");
throw e;
}
}
}
通常,如果切入点在多个aspect之间共享,最好将它们集中到一个公共类中。在这种情况下,它们必须声明为public。
package com.codeproject.jackie.springrecipesnote.springaop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author jackie
*
*/
@Aspect
public class CalculatorPointcuts {
@Pointcut("execution(* *.*(..))")
public void loggingOperation() {
}
}
当引用这个切入点时,必须包含类名。如果类不在与这个aspect相同的包中,还必须包含包名。
@Before("CalculatorPointcuts.loggingOperation()")
public void logBefore(JoinPoint joinPoint) {
log.info("The method " + joinPoint.getSignature().getName()
+ "() begins with " + Arrays.toString(joinPoint.getArgs()));
}
@After("CalculatorPointcuts.loggingOperation()")
public void logAfter(JoinPoint joinPoint) {
log.info("The method " + joinPoint.getSignature().getName() + "() ends");
}
@AfterReturning(pointcut = "CalculatorPointcuts.loggingOperation())", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
}
@AfterThrowing(pointcut = "CalculatorPointcuts.loggingOperation())", throwing = "e")
public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
log.error("An exception " + e + " has been thrown in " + joinPoint.getSignature().getName() + "()");
}
@Around("CalculatorPointcuts.loggingOperation()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("The method " + joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs()));
try {
Object result = joinPoint.proceed();
log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument " + Arrays.toString(joinPoint.getArgs()) + " in " + joinPoint.getSignature().getName() + "()");
throw e;
}
}当相同连接点上应用了多个aspect时,aspect的优先级是不明确的,除非显式地指定它们的优先级。
aspect的优先级可以通过实现Ordered接口或者使用@Order注解实现。
二、代码示例
(1)实现Ordered接口
package com.codeproject.jackie.springrecipesnote.springaop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.Ordered;
/**
* @author jackie
*
*/
@Aspect
public class CalculatorValidationAspect implements Ordered{
private Log log = LogFactory.getLog(this.getClass());
@Before("execution(* *.*(double, double))")
public void validateBefore(JoinPoint joinPoint) {
for (Object arg : joinPoint.getArgs()) {
log.info("validate begins...");
validate((Double) arg);
}
}
private void validate(Double arg) {
if (arg < 0) {
throw new IllegalArgumentException("Positive numbers only");
}
}
@Override
public int getOrder() {
return 0;
}
}
package com.codeproject.jackie.springrecipesnote.springaop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.Ordered;
/**
* @author jackie
*
*/
@Aspect
public class CalculatorLoggingAspect implements Ordered{
private Log log = LogFactory.getLog(this.getClass());
/**
* 切入点表达式匹配ArithmeticCalculator接口的add()方法的执行。
* 表达式前导的星号匹配任何修饰符(public、protected和private)和任何返回类型。
* 参数列表中的两个点匹配任何数量的参数。
*/
@Before("execution(* ArithmeticCalculator.add(..))")
public void logBefore() {
log.info("The method add() begins");
}
@Override
public int getOrder() {
return 1;
}
}
只要在Bean配置文件中声明这个aspect的一个Bean实例,就可以在Spring中注册这个aspect:
<bean class="com.codeproject.jackie.springrecipesnote.springaop.CalculatorLoggingAspect" /> <bean class="com.codeproject.jackie.springrecipesnote.springaop.CalculatorValidationAspect" />
注意:aspect的优先级不取决于Bean声明的顺序。getOrder()方法返回的值越低就代表越高的优先级。
(2)@Order注解另一种指定优先级的方法是通过@Order注解。顺序值在注解值中出现。
package com.codeproject.jackie.springrecipesnote.springaop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
/**
* @author jackie
*
*/
@Aspect
@Order(0)
public class CalculatorValidationAspect {
private Log log = LogFactory.getLog(this.getClass());
@Before("execution(* *.*(double, double))")
public void validateBefore(JoinPoint joinPoint) {
for (Object arg : joinPoint.getArgs()) {
log.info("validate begins...");
validate((Double) arg);
}
}
private void validate(Double arg) {
if (arg < 0) {
throw new IllegalArgumentException("Positive numbers only");
}
}
}
package com.codeproject.jackie.springrecipesnote.springaop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
/**
* @author jackie
*
*/
@Aspect
@Order(1)
public class CalculatorLoggingAspect{
private Log log = LogFactory.getLog(this.getClass());
/**
* 切入点表达式匹配ArithmeticCalculator接口的add()方法的执行。
* 表达式前导的星号匹配任何修饰符(public、protected和private)和任何返回类型。
* 参数列表中的两个点匹配任何数量的参数。
*/
@Before("execution(* ArithmeticCalculator.add(..))")
public void logBefore() {
log.info("The method add() begins");
}
}