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

Commit 80e907ed authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add ExemptAidlInterfacesGenerator for PermissionAnnotationDetector" into main

parents 2a316dac 4f522ff2
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -24,20 +24,31 @@ import com.intellij.psi.PsiReferenceList
import org.jetbrains.uast.UMethod

/**
 * Given a UMethod, determine if this method is the entrypoint to an interface
 * generated by AIDL, returning the interface name if so, otherwise returning
 * null
 * Given a UMethod, determine if this method is the entrypoint to an interface generated by AIDL,
 * returning the interface name if so, otherwise returning null.
 */
fun getContainingAidlInterface(context: JavaContext, node: UMethod): String? {
    return containingAidlInterfacePsiClass(context, node)?.name
}

/**
 * Given a UMethod, determine if this method is the entrypoint to an interface generated by AIDL,
 * returning the fully qualified interface name if so, otherwise returning null.
 */
fun getContainingAidlInterfaceQualified(context: JavaContext, node: UMethod): String? {
    return containingAidlInterfacePsiClass(context, node)?.qualifiedName
}

private fun containingAidlInterfacePsiClass(context: JavaContext, node: UMethod): PsiClass? {
    val containingStub = containingStub(context, node) ?: return null
    val superMethod = node.findSuperMethods(containingStub)
    if (superMethod.isEmpty()) return null
    return containingStub.containingClass?.name
    return containingStub.containingClass
}

/* Returns the containing Stub class if any. This is not sufficient to infer
 * that the method itself extends an AIDL generated method. See
 * getContainingAidlInterface for that purpose.
/**
 * Returns the containing Stub class if any. This is not sufficient to infer that the method itself
 * extends an AIDL generated method. See getContainingAidlInterface for that purpose.
 */
fun containingStub(context: JavaContext, node: UMethod?): PsiClass? {
    var superClass = node?.containingClass?.superClass
@@ -48,7 +59,7 @@ fun containingStub(context: JavaContext, node: UMethod?): PsiClass? {
    return null
}

private fun isStub(context: JavaContext, psiClass: PsiClass?): Boolean {
fun isStub(context: JavaContext, psiClass: PsiClass?): Boolean {
    if (psiClass == null) return false
    if (psiClass.name != "Stub") return false
    if (!context.evaluator.isStatic(psiClass)) return false
+774 −0

File added.

Preview size limit exceeded, changes collapsed.

+11 −0
Original line number Diff line number Diff line
# Utility Android Lint Checks for AOSP

This directory contains scripts that execute utility Android Lint Checks for AOSP, specifically:
* `enforce_permission_counter.py`: Provides statistics regarding the percentage of annotated/not
  annotated `AIDL` methods with `@EnforcePermission` annotations.
* `generate-exempt-aidl-interfaces.sh`: Provides a list of all `AIDL` interfaces in the entire
  source tree.

When adding a new utility Android Lint check to this directory, consider adding any utility or
data processing tool you might require. Make sure that your contribution is documented in this
README file.
+3 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.google.android.lint
import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.client.api.Vendor
import com.android.tools.lint.detector.api.CURRENT_API
import com.google.android.lint.aidl.ExemptAidlInterfacesGenerator
import com.google.android.lint.aidl.AnnotatedAidlCounter
import com.google.auto.service.AutoService

@@ -27,6 +28,7 @@ import com.google.auto.service.AutoService
class AndroidUtilsIssueRegistry : IssueRegistry() {
    override val issues = listOf(
        AnnotatedAidlCounter.ISSUE_ANNOTATED_AIDL_COUNTER,
        ExemptAidlInterfacesGenerator.ISSUE_PERMISSION_ANNOTATION_EXEMPT_AIDL_INTERFACES,
    )

    override val api: Int
@@ -38,6 +40,6 @@ class AndroidUtilsIssueRegistry : IssueRegistry() {
    override val vendor: Vendor = Vendor(
        vendorName = "Android",
        feedbackUrl = "http://b/issues/new?component=315013",
        contact = "tweek@google.com"
        contact = "android-platform-abuse-prevention-withfriends@google.com"
    )
}
+96 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 com.google.android.lint.aidl

import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Context
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import org.jetbrains.uast.UBlockExpression
import org.jetbrains.uast.UMethod

/**
 * Generates a set of fully qualified AIDL Interface names present in the entire source tree with
 * the following requirement: their implementations have to be inside directories whose path
 * prefixes match `systemServicePathPrefixes`.
 */
class ExemptAidlInterfacesGenerator : AidlImplementationDetector() {
    private val targetExemptAidlInterfaceNames = mutableSetOf<String>()
    private val systemServicePathPrefixes = setOf(
        "frameworks/base/services",
        "frameworks/base/apex",
        "frameworks/opt/wear",
        "packages/modules"
    )

    // We could've improved performance by visiting classes rather than methods, however, this lint
    // check won't be run regularly, hence we've decided not to add extra overrides to
    // AidlImplementationDetector.
    override fun visitAidlMethod(
        context: JavaContext,
        node: UMethod,
        interfaceName: String,
        body: UBlockExpression
    ) {
        val filePath = context.file.path

        // We perform `filePath.contains` instead of `filePath.startsWith` since getting the
        // relative path of a source file is non-trivial. That is because `context.file.path`
        // returns the path to where soong builds the file (i.e. /out/soong/...). Moreover, the
        // logic to extract the relative path would need to consider several /out/soong/...
        // locations patterns.
        if (systemServicePathPrefixes.none { filePath.contains(it) }) return

        val fullyQualifiedInterfaceName =
            getContainingAidlInterfaceQualified(context, node) ?: return

        targetExemptAidlInterfaceNames.add("\"$fullyQualifiedInterfaceName\",")
    }

    override fun afterCheckEachProject(context: Context) {
        if (targetExemptAidlInterfaceNames.isEmpty()) return

        val message = targetExemptAidlInterfaceNames.joinToString("\n")

        context.report(
            ISSUE_PERMISSION_ANNOTATION_EXEMPT_AIDL_INTERFACES,
            context.getLocation(context.project.dir),
            "\n" + message + "\n",
        )
    }

    companion object {
        @JvmField
        val ISSUE_PERMISSION_ANNOTATION_EXEMPT_AIDL_INTERFACES = Issue.create(
            id = "PermissionAnnotationExemptAidlInterfaces",
            briefDescription = "Returns a set of all AIDL interfaces",
            explanation = """
                Produces the exemptAidlInterfaces set used by PermissionAnnotationDetector
            """.trimIndent(),
            category = Category.SECURITY,
            priority = 5,
            severity = Severity.INFORMATIONAL,
            implementation = Implementation(
                ExemptAidlInterfacesGenerator::class.java,
                Scope.JAVA_FILE_SCOPE
            )
        )
    }
}
Loading