1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.android.lint.aidl 18 19 import com.android.tools.lint.detector.api.Category 20 import com.android.tools.lint.detector.api.Implementation 21 import com.android.tools.lint.detector.api.Issue 22 import com.android.tools.lint.detector.api.JavaContext 23 import com.android.tools.lint.detector.api.Scope 24 import com.android.tools.lint.detector.api.Severity 25 import org.jetbrains.uast.UBlockExpression 26 import org.jetbrains.uast.UMethod 27 28 /** 29 * Ensures all AIDL-generated methods are annotated. 30 * 31 * This detector is run on system_server to validate that any method that may 32 * be exposed via an AIDL interface is permission-annotated. That is, it must 33 * have one of the following annotation: 34 * - @EnforcePermission 35 * - @RequiresNoPermission 36 * - @PermissionManuallyEnforced 37 */ 38 class PermissionAnnotationDetector : AidlImplementationDetector() { 39 visitAidlMethodnull40 override fun visitAidlMethod( 41 context: JavaContext, 42 node: UMethod, 43 interfaceName: String, 44 body: UBlockExpression 45 ) { 46 if (!isSystemServicePath(context)) return 47 48 if (context.evaluator.isAbstract(node)) return 49 50 val fullyQualifiedInterfaceName = 51 getContainingAidlInterfaceQualified(context, node) ?: return 52 if (exemptAidlInterfaces.contains(fullyQualifiedInterfaceName)) return 53 54 if (AIDL_PERMISSION_ANNOTATIONS.any { node.hasAnnotation(it) }) return 55 56 context.report( 57 ISSUE_MISSING_PERMISSION_ANNOTATION, 58 node, 59 context.getLocation(node), 60 """ 61 ${node.name} should be annotated with either @EnforcePermission, \ 62 @RequiresNoPermission or @PermissionManuallyEnforced. 63 """.trimMargin() 64 ) 65 } 66 67 companion object { 68 69 private val EXPLANATION_MISSING_PERMISSION_ANNOTATION = """ 70 Interfaces that are exposed by system_server are required to have an annotation which 71 denotes the type of permission enforced. There are 3 possible options: 72 - @EnforcePermission 73 - @RequiresNoPermission 74 - @PermissionManuallyEnforced 75 See the documentation of each annotation for further details. 76 77 The annotation on the Java implementation must be the same that the AIDL interface 78 definition. This is verified by a lint in the build system. 79 """.trimIndent() 80 81 @JvmField 82 val ISSUE_MISSING_PERMISSION_ANNOTATION = Issue.create( 83 id = "MissingPermissionAnnotation", 84 briefDescription = "No permission annotation on exposed AIDL interface.", 85 explanation = EXPLANATION_MISSING_PERMISSION_ANNOTATION, 86 category = Category.CORRECTNESS, 87 priority = 5, 88 severity = Severity.ERROR, 89 implementation = Implementation( 90 PermissionAnnotationDetector::class.java, 91 Scope.JAVA_FILE_SCOPE 92 ) 93 ) 94 } 95 } 96