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

Commit 9469a8e8 authored by Peter Kalauskas's avatar Peter Kalauskas Committed by Automerger Merge Worker
Browse files

Merge "New detector for getCurrentUser and getUserInfo" into tm-qpr-dev am:...

Merge "New detector for getCurrentUser and getUserInfo" into tm-qpr-dev am: c666fc8d am: 6bf13e3b

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19906016



Change-Id: I4906d4465669494a7645179913afa4b884ed57f7
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents fd56fe87 6bf13e3b
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.internal.systemui.lint

import com.android.tools.lint.detector.api.Category
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

/**
 * Checks for slow calls to ActivityManager.getCurrentUser() or UserManager.getUserInfo() and
 * suggests using UserTracker instead. For more info, see: http://go/multi-user-in-systemui-slides.
 */
@Suppress("UnstableApiUsage")
class SlowUserQueryDetector : Detector(), SourceCodeScanner {

    override fun getApplicableMethodNames(): List<String> {
        return listOf("getCurrentUser", "getUserInfo")
    }

    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
        val evaluator = context.evaluator
        if (
            evaluator.isStatic(method) &&
                method.name == "getCurrentUser" &&
                method.containingClass?.qualifiedName == "android.app.ActivityManager"
        ) {
            context.report(
                ISSUE_SLOW_USER_ID_QUERY,
                method,
                context.getNameLocation(node),
                "ActivityManager.getCurrentUser() is slow. " +
                    "Use UserTracker.getUserId() instead."
            )
        }
        if (
            !evaluator.isStatic(method) &&
                method.name == "getUserInfo" &&
                method.containingClass?.qualifiedName == "android.os.UserManager"
        ) {
            context.report(
                ISSUE_SLOW_USER_INFO_QUERY,
                method,
                context.getNameLocation(node),
                "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
            )
        }
    }

    companion object {
        @JvmField
        val ISSUE_SLOW_USER_ID_QUERY: Issue =
            Issue.create(
                id = "SlowUserIdQuery",
                briefDescription = "User ID queried using ActivityManager instead of UserTracker.",
                explanation =
                    "ActivityManager.getCurrentUser() makes a binder call and is slow. " +
                        "Instead, inject a UserTracker and call UserTracker.getUserId(). For " +
                        "more info, see: http://go/multi-user-in-systemui-slides",
                category = Category.PERFORMANCE,
                priority = 8,
                severity = Severity.WARNING,
                implementation =
                    Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
            )

        @JvmField
        val ISSUE_SLOW_USER_INFO_QUERY: Issue =
            Issue.create(
                id = "SlowUserInfoQuery",
                briefDescription = "User info queried using UserManager instead of UserTracker.",
                explanation =
                    "UserManager.getUserInfo() makes a binder call and is slow. " +
                        "Instead, inject a UserTracker and call UserTracker.getUserInfo(). For " +
                        "more info, see: http://go/multi-user-in-systemui-slides",
                category = Category.PERFORMANCE,
                priority = 8,
                severity = Severity.WARNING,
                implementation =
                    Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
            )
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,8 @@ class SystemUIIssueRegistry : IssueRegistry() {
        get() = listOf(
                BindServiceViaContextDetector.ISSUE,
                BroadcastSentViaContextDetector.ISSUE,
                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
                GetMainLooperViaContextDetector.ISSUE,
                RegisterReceiverViaContextDetector.ISSUE,
                SoftwareBitmapDetector.ISSUE,
+194 −0
Original line number Diff line number Diff line
package com.android.internal.systemui.lint

import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFile
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test

class SlowUserQueryDetectorTest : LintDetectorTest() {

    override fun getDetector(): Detector = SlowUserQueryDetector()
    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)

    override fun getIssues(): List<Issue> =
        listOf(
            SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
            SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
        )

    @Test
    fun testGetCurrentUser() {
        lint()
            .files(
                TestFiles.java(
                        """
                        package test.pkg;
                        import android.app.ActivityManager;

                        public class TestClass1 {
                            public void slewlyGetCurrentUser() {
                                ActivityManager.getCurrentUser();
                            }
                        }
                        """
                    )
                    .indented(),
                *stubs
            )
            .issues(
                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
            )
            .run()
            .expectWarningCount(1)
            .expectContains(
                "ActivityManager.getCurrentUser() is slow. " +
                    "Use UserTracker.getUserId() instead."
            )
    }

    @Test
    fun testGetUserInfo() {
        lint()
            .files(
                TestFiles.java(
                        """
                        package test.pkg;
                        import android.os.UserManager;

                        public class TestClass2 {
                            public void slewlyGetUserInfo(UserManager userManager) {
                                userManager.getUserInfo();
                            }
                        }
                        """
                    )
                    .indented(),
                *stubs
            )
            .issues(
                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
            )
            .run()
            .expectWarningCount(1)
            .expectContains(
                "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
            )
    }

    @Test
    fun testUserTrackerGetUserId() {
        lint()
            .files(
                TestFiles.java(
                        """
                        package test.pkg;
                        import com.android.systemui.settings.UserTracker;

                        public class TestClass3 {
                            public void quicklyGetUserId(UserTracker userTracker) {
                                userTracker.getUserId();
                            }
                        }
                        """
                    )
                    .indented(),
                *stubs
            )
            .issues(
                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
            )
            .run()
            .expectClean()
    }

    @Test
    fun testUserTrackerGetUserInfo() {
        lint()
            .files(
                TestFiles.java(
                        """
                        package test.pkg;
                        import com.android.systemui.settings.UserTracker;

                        public class TestClass4 {
                            public void quicklyGetUserId(UserTracker userTracker) {
                                userTracker.getUserInfo();
                            }
                        }
                        """
                    )
                    .indented(),
                *stubs
            )
            .issues(
                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
            )
            .run()
            .expectClean()
    }

    private val activityManagerStub: TestFile =
        java(
            """
            package android.app;

            public class ActivityManager {
                public static int getCurrentUser() {};
            }
            """
        )

    private val userManagerStub: TestFile =
        java(
            """
            package android.os;
            import android.content.pm.UserInfo;
            import android.annotation.UserIdInt;

            public class UserManager {
                public UserInfo getUserInfo(@UserIdInt int userId) {};
            }
            """
        )

    private val userIdIntStub: TestFile =
        java(
            """
            package android.annotation;

            public @interface UserIdInt {}
            """
        )

    private val userInfoStub: TestFile =
        java(
            """
            package android.content.pm;

            public class UserInfo {}
            """
        )

    private val userTrackerStub: TestFile =
        java(
            """
            package com.android.systemui.settings;
            import android.content.pm.UserInfo;

            public interface UserTracker {
                public int getUserId();
                public UserInfo getUserInfo();
            }
            """
        )

    private val stubs =
        arrayOf(activityManagerStub, userManagerStub, userIdIntStub, userInfoStub, userTrackerStub)
}