1 /* 2 * Copyright (C) 2021 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 18 19 import com.android.tools.lint.detector.api.Category 20 import com.android.tools.lint.detector.api.Detector 21 import com.android.tools.lint.detector.api.Implementation 22 import com.android.tools.lint.detector.api.Issue 23 import com.android.tools.lint.detector.api.JavaContext 24 import com.android.tools.lint.detector.api.Scope 25 import com.android.tools.lint.detector.api.Severity 26 import com.android.tools.lint.detector.api.SourceCodeScanner 27 import com.intellij.psi.PsiMethod 28 import org.jetbrains.uast.UCallExpression 29 30 /** 31 * Lint Detector that finds issues with improper usages of the non-user getter methods of Settings 32 */ 33 @Suppress("UnstableApiUsage") 34 class CallingSettingsNonUserGetterMethodsDetector : Detector(), SourceCodeScanner { 35 override fun getApplicableMethodNames(): List<String> = listOf( 36 "getString", 37 "getInt", 38 "getLong", 39 "getFloat" 40 ) 41 42 override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) { 43 val evaluator = context.evaluator 44 if (evaluator.isMemberInClass(method, "android.provider.Settings.Secure") || 45 evaluator.isMemberInClass(method, "android.provider.Settings.System") 46 ) { 47 val message = getIncidentMessageNonUserGetterMethods(getMethodSignature(method)) 48 context.report(ISSUE_NON_USER_GETTER_CALLED, node, context.getNameLocation(node), 49 message) 50 } 51 } 52 53 private fun getMethodSignature(method: PsiMethod) = 54 method.containingClass 55 ?.qualifiedName 56 ?.let { "$it#${method.name}" } 57 ?: method.name 58 59 companion object { 60 @JvmField 61 val ISSUE_NON_USER_GETTER_CALLED: Issue = Issue.create( 62 id = "NonUserGetterCalled", 63 briefDescription = "Non-ForUser Getter Method called to Settings", 64 explanation = """ 65 System process should not call the non-ForUser getter methods of \ 66 `Settings.Secure` or `Settings.System`. For example, instead of \ 67 `Settings.Secure.getInt()`, use `Settings.Secure.getIntForUser()` instead. \ 68 This will make sure that the correct Settings value is retrieved. 69 """, 70 category = Category.CORRECTNESS, 71 priority = 6, 72 severity = Severity.ERROR, 73 implementation = Implementation( 74 CallingSettingsNonUserGetterMethodsDetector::class.java, 75 Scope.JAVA_FILE_SCOPE 76 ) 77 ) 78 79 fun getIncidentMessageNonUserGetterMethods(methodSignature: String) = 80 "`$methodSignature()` called from system process. " + 81 "Please call `${methodSignature}ForUser()` instead. " 82 } 83 } 84