Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e63cb8fa authored by Thiébaud Weksteen's avatar Thiébaud Weksteen
Browse files

Support @EnforcePermission annotation

Update RequiresPermissionChecker to support a method annotated with
@EnforcePermission. If encountered, we assume that the implementation is
enforcing the declared permissions (this is verified by another linter).

Bug: 239369037
Test: atest --host error_prone_android_framework_test
Change-Id: I25deb47acc1259a1171954aeebd72eb60f01fc49
parent 31e1f9f8
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.google.errorprone.matchers.Matchers.methodInvocation;
import static com.google.errorprone.matchers.Matchers.methodIsNamed;
import static com.google.errorprone.matchers.Matchers.staticMethod;

import android.annotation.EnforcePermission;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;

@@ -290,6 +291,13 @@ public final class RequiresPermissionChecker extends BugChecker
            if (perm.anyOf() != null) this.anyOf.addAll(Arrays.asList(perm.anyOf()));
        }

        public void addAll(EnforcePermission perm) {
            if (perm == null) return;
            if (!perm.value().isEmpty()) this.allOf.add(perm.value());
            if (perm.allOf() != null) this.allOf.addAll(Arrays.asList(perm.allOf()));
            if (perm.anyOf() != null) this.anyOf.addAll(Arrays.asList(perm.anyOf()));
        }

        public void addConstValue(Tree tree) {
            final Object value = ASTHelpers.constValue(tree);
            if (value != null) {
@@ -416,14 +424,20 @@ public final class RequiresPermissionChecker extends BugChecker
            final ParsedRequiresPermission res = new ParsedRequiresPermission();
            res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(0))));
            return res;
        } else if (ENFORCE_VIA_CHECKER.matches(tree, state) && tree.getArguments().size() > 1) {
        }
        if (ENFORCE_VIA_CHECKER.matches(tree, state) && tree.getArguments().size() > 1) {
            final ParsedRequiresPermission res = new ParsedRequiresPermission();
            res.allOf.add(String.valueOf(ASTHelpers.constValue(tree.getArguments().get(1))));
            return res;
        } else {
        }
        final MethodSymbol method = ASTHelpers.getSymbol(tree);
            return parseRequiresPermissionRecursively(method, state);
        final EnforcePermission enforced = method.getAnnotation(EnforcePermission.class);
        if (enforced != null) {
            final ParsedRequiresPermission res = new ParsedRequiresPermission();
            res.addAll(enforced);
            return res;
        }
        return parseRequiresPermissionRecursively(method, state);
    }

    /**
+39 −0
Original line number Diff line number Diff line
@@ -438,4 +438,43 @@ public class RequiresPermissionCheckerTest {
                        "}")
                .doTest();
    }

    @Test
    public void testEnforce() {
        compilationHelper
                .addSourceFile("/android/annotation/EnforcePermission.java")
                .addSourceFile("/android/content/Context.java")
                .addSourceFile("/android/foo/IBarService.java")
                .addSourceFile("/android/os/IInterface.java")
                .addSourceLines("BarService.java",
                        "import android.annotation.EnforcePermission;",
                        "import android.foo.IBarService;",
                        "class BarService extends IBarService.Stub {",
                        "  @Override",
                        "  @EnforcePermission(\"INTERNET\")",
                        "  public void bar() {",
                        "    bar_enforcePermission();",
                        "  }",
                        "}")
                .addSourceLines("BarManager.java",
                        "import android.annotation.RequiresPermission;",
                        "class BarManager {",
                        "  BarService mService;",
                        "  @RequiresPermission(\"INTERNET\")",
                        "  public void callBar() {",
                        "    mService.bar();",
                        "  }",
                        "  @RequiresPermission(\"NONE\")",
                        "  public void callBarDifferent() {",
                        "    // BUG: Diagnostic contains:",
                        "    mService.bar();",
                        "  }",
                        "  public void callBarMissing() {",
                        "    // BUG: Diagnostic contains:",
                        "    mService.bar();",
                        "  }",
                        "}")
                .doTest();
    }

}
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.annotation;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.CLASS;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(CLASS)
@Target({METHOD})
public @interface EnforcePermission {
    String value() default "";
    String[] allOf() default {};
    String[] anyOf() default {};
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.foo;

import android.annotation.EnforcePermission;

public interface IBarService extends android.os.IInterface {
    @EnforcePermission("INTERNET")
    void bar();

    abstract class Stub implements IBarService {
        public void bar_enforcePermission() { }
    }
}