Skip to content

AOP 多注解出现失效或发生异常(EmptyStackException) #60

@880634

Description

@880634

请提供构建环境相关信息:

  • 当前使用的插件版本:3.3.1

  • AGP(Android Gradle Plugin)版本:7.1.0

  • Gradle版本:7.2-all.zip

发送构建错误时,请先确定是构建错误还是aspectj织入错误:

已自查,并没有找到对应的记录

  • 如果是aspectj织入发生异常,会在对应module下的build/tmp/transformClassesWithAjxForXXX/logs目录下产生ajcore为前缀的日志文件,请提供该日志文件以便查找问题

非编译时的问题,而是运行时的问题

  • 如果是其它错误,请尽量提供完整的堆栈信息
W/System.err: java.util.EmptyStackException
W/System.err:     at java.util.Stack.peek(Stack.java:102)
W/System.err:     at org.aspectj.runtime.reflect.JoinPointImpl.proceed(JoinPointImpl.java:170)
W/System.err:     at com.hjq.demo.aop.PermissionsAspect$1.onGranted(PermissionsAspect.java:78)
W/System.err:     at com.hjq.demo.other.PermissionInterceptor.grantedPermissionRequest(PermissionInterceptor.java:123)
W/System.err:     at com.hjq.permissions.PermissionFragment.onRequestPermissionsResult(PermissionFragment.java:394)
W/System.err:     at android.app.Activity.dispatchRequestPermissionsResultToFragment(Activity.java:7626)
W/System.err:     at android.app.Activity.dispatchActivityResult(Activity.java:7470)
W/System.err:     at android.app.ActivityThread.deliverResults(ActivityThread.java:4391)
W/System.err:     at android.app.ActivityThread.handleSendResult(ActivityThread.java:4440)
W/System.err:     at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
W/System.err:     at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
W/System.err:     at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:106)
W/System.err:     at android.os.Looper.loop(Looper.java:193)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6718)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
  • 其他相关代码
@Aspect
public class PermissionsAspect {

    /**
     * 方法切入点
     */
    @Pointcut("execution(@com.hjq.demo.aop.Permissions * *(..))")
    public void method() {}

    /**
     * 在连接点进行方法替换
     */
    @Around("method() && @annotation(permissions)")
    public void aroundJoinPoint(ProceedingJoinPoint joinPoint, Permissions permissions) {
        Activity activity = null;

        // 方法参数值集合
        Object[] parameterValues = joinPoint.getArgs();
        for (Object arg : parameterValues) {
            if (!(arg instanceof Activity)) {
                continue;
            }
            activity = (Activity) arg;
            break;
        }

        if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
            activity = ActivityManager.getInstance().getTopActivity();
        }

        if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
            Timber.e("The activity has been destroyed and permission requests cannot be made");
            return;
        }

        requestPermissions(joinPoint, activity, permissions.value());
    }

    private void requestPermissions(ProceedingJoinPoint joinPoint, Activity activity, String[] permissions) {
        XXPermissions.with(activity)
                .permission(permissions)
                .interceptor(new PermissionInterceptor())
                .request(new OnPermissionCallback() {

                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        if (allGranted) {
                            try {
                                // 获得权限,执行原方法
                                joinPoint.proceed();
                            } catch (Throwable e) {
                                e.printStackTrace();
                                CrashReport.postCatchedException(e);
                            }
                        }
                    }
                });
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Permissions {

    /**
     * 需要申请权限的集合
     */
    String[] value();
}
@Aspect
public class LogAspect {

    /**
     * 构造方法切入点
     */
    @Pointcut("execution(@com.hjq.demo.aop.Log *.new(..))")
    public void constructor() {}

    /**
     * 方法切入点
     */
    @Pointcut("execution(@com.hjq.demo.aop.Log * *(..))")
    public void method() {}

    /**
     * 在连接点进行方法替换
     */
    @Around("(method() || constructor()) && @annotation(log)")
    public Object aroundJoinPoint(ProceedingJoinPoint joinPoint, Log log) throws Throwable {
        enterMethod(joinPoint, log);

        long startNanos = System.nanoTime();
        Object result = joinPoint.proceed();
        long stopNanos = System.nanoTime();

        exitMethod(joinPoint, log, result, TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos));

        return result;
    }

    /**
     * 方法执行前切入
     */
    private void enterMethod(ProceedingJoinPoint joinPoint, Log log) {
        CodeSignature codeSignature = (CodeSignature) joinPoint.getSignature();

        // 方法所在类
        String className = codeSignature.getDeclaringType().getName();
        // 方法名
        String methodName = codeSignature.getName();
        // 方法参数名集合
        String[] parameterNames = codeSignature.getParameterNames();
        // 方法参数值集合
        Object[] parameterValues = joinPoint.getArgs();

        //记录并打印方法的信息
        StringBuilder builder = getMethodLogInfo(className, methodName, parameterNames, parameterValues);

        log(log.value(), builder.toString());

        final String section = builder.substring(2);
        Trace.beginSection(section);
    }

    /**
     * 获取方法的日志信息
     *
     * @param className         类名
     * @param methodName        方法名
     * @param parameterNames    方法参数名集合
     * @param parameterValues   方法参数值集合
     */
    @NonNull
    private StringBuilder getMethodLogInfo(String className, String methodName, String[] parameterNames, Object[] parameterValues) {
        StringBuilder builder = new StringBuilder("\u21E2 ");
        builder.append(className)
                .append(".")
                .append(methodName)
                .append('(');
        for (int i = 0; i < parameterValues.length; i++) {
            if (i > 0) {
                builder.append(", ");
            }
            builder.append(parameterNames[i]).append('=');
            builder.append(parameterValues[i]);
        }
        builder.append(')');

        if (Looper.myLooper() != Looper.getMainLooper()) {
            builder.append(" [Thread:\"").append(Thread.currentThread().getName()).append("\"]");
        }
        return builder;
    }

    /**
     * 方法执行完毕,切出
     *
     * @param result            方法执行后的结果
     * @param lengthMillis      执行方法所需要的时间
     */
    private void exitMethod(ProceedingJoinPoint joinPoint, Log log, Object result, long lengthMillis) {
        Trace.endSection();

        Signature signature = joinPoint.getSignature();

        String className = signature.getDeclaringType().getName();
        String methodName = signature.getName();

        StringBuilder builder = new StringBuilder("\u21E0 ")
                .append(className)
                .append(".")
                .append(methodName)
                .append(" [")
                .append(lengthMillis)
                .append("ms]");

        //  判断方法是否有返回值
        if (signature instanceof MethodSignature && ((MethodSignature) signature).getReturnType() != void.class) {
            builder.append(" = ");
            builder.append(result.toString());
        }

        log(log.value(), builder.toString());
    }

    private void log(String tag, String msg) {
        Timber.tag(tag);
        Timber.d(msg);
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Log {

    String value() default "AOPLog";
}
public final class ImageSelectActivity extends AppActivity {

    .....

    @Log
    @Permissions({Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE})
    public static void start(BaseActivity activity, int maxSelect, OnPhotoSelectListener listener) {
        .....
    }
    .....
}
  • 问题原因

我在某个方法上面加了两个 AOP 注解,一个是打印方法名及参数的 Log 的 AOP 注解,另外一个是请求权限的 AOP 注解,现在出现了一种情况,权限回调中有正常调用 joinPoint.proceed(),但是会出现 java.util.EmptyStackException 异常,最终导致切面无法往下执行。

  • 问题排查

我如果删掉 Log AOP 注解,则就没有异常了。又或者权限是授予状态,也是没有问题的,因为调用 XXPermissions 申请权限的时候,它会先判断授权有没有授予,有的话会直接回调授予的方法(同步操作),如果没有授予权限的话,则会开启一个透明的 Fragment 来发起申请权限(异步操作),可能是因为这个原因不行的,但是权限框架这样做是没有问题的。

之前使用 HujiangTechnology/gradle_plugin_android_aspectjx 是没有问题的,现在换成了 wurensen/gradle_plugin_android_aspectjx 就报这个错了,劳烦大大有空看一下

Metadata

Metadata

Assignees

No one assigned

    Labels

    wontfixThis will not be worked on

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions