blob: acc363ecfc744214e8fea52efd02a11bf97a9142 [file] [log] [blame]
/*
* Copyright (C) 2020 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.android.tools.lint.checks
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.ConstantEvaluator
import com.android.tools.lint.detector.api.Detector
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 com.android.tools.lint.detector.api.SourceCodeScanner
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.UCallExpression
class PendingIntentMutableFlagDetector : Detector(), SourceCodeScanner {
override fun getApplicableMethodNames() = METHOD_NAMES
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
if (!context.evaluator.isMemberInClass(method, "android.app.PendingIntent"))
return
val flagsArgument = node.getArgumentForParameter(FLAG_ARGUMENT_POSITION) ?: return
val flags = ConstantEvaluator.evaluate(context, flagsArgument) as? Int ?: return
if (flags and FLAG_MASK == 0) {
context.report(
ISSUE,
node,
context.getLocation(flagsArgument),
"Missing `PendingIntent` mutability flag"
)
}
}
companion object {
private val METHOD_NAMES =
listOf("getActivity", "getActivities", "getBroadcast", "getService")
private const val FLAG_ARGUMENT_POSITION = 3
private const val FLAG_IMMUTABLE = 1 shl 26
private const val FLAG_MUTABLE = 1 shl 25
private const val FLAG_MASK = FLAG_IMMUTABLE or FLAG_MUTABLE
@JvmField
val ISSUE = Issue.create(
id = "UnspecifiedImmutableFlag",
briefDescription = "Missing `PendingIntent` mutability flag",
explanation = """
Apps targeting Android 12 and higher must specify either `FLAG_IMMUTABLE` or \
`FLAG_MUTABLE` when constructing a `PendingIntent`.
""",
category = Category.SECURITY,
priority = 5,
severity = Severity.WARNING,
implementation = Implementation(
PendingIntentMutableFlagDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}
}