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

Commit 0e7dca65 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

HostStubGen: Fix direct outer class detection

If there's a nested class like A$B$C and C doesn't have a class-wide
policy, HSG was supposed to look at A$B's ("direct outer class") policy,
but it was using A's policy. Fixed it.

Bug: 311174191
Test: ./scripts/run-all-tests.sh
Test: atest --host CtsGraphicsTestCasesRavenwood \
    CtsTextTestCasesRavenwood \
    CtsOsTestCasesRavenwood \
    CtsAccountManagerTestCasesRavenwood \
    CtsContentTestCasesRavenwood \
    CtsProtoTestCasesRavenwood \
    CtsUtilTestCasesRavenwood \
    CtsDatabaseTestCasesRavenwood
Change-Id: I4881caac5e91366cf60e1aa232ecaf6b7c88aecf
parent fd5e8197
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -158,7 +158,7 @@ class HostStubGen(val options: HostStubGenOptions) {
        // This is used when a member (methods, fields, nested classes) don't get any polices
        // from upper filters. e.g. when a method has no annotations, then this filter will apply
        // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
        filter = ClassWidePolicyPropagatingFilter(filter)
        filter = ClassWidePolicyPropagatingFilter(allClasses, filter)

        // Inject default hooks from options.
        filter = DefaultHookInjectingFilter(
+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ fun isAnonymousInnerClass(cn: ClassNode): Boolean {
 * Otherwise, return null.
 */
fun getDirectOuterClassName(className: String): String? {
    val pos = className.indexOf('$')
    val pos = className.lastIndexOf('$')
    if (pos < 0) {
        return null
    }
+26 −9
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.hoststubgen.filters

import com.android.hoststubgen.asm.ClassNodes
import com.android.hoststubgen.asm.getDirectOuterClassName

/**
@@ -22,24 +23,40 @@ import com.android.hoststubgen.asm.getDirectOuterClassName
 * (obtained from [outermostFilter]) to the fields and methods.
 */
class ClassWidePolicyPropagatingFilter(
    private val classes: ClassNodes,
    fallback: OutputFilter,
    ) : DelegatingFilter(fallback) {

    private fun getClassWidePolicy(className: String, resolve: Boolean): FilterPolicyWithReason? {
        var currentClass = className


        // If the class name is `a.b.c.A$B$C`, then we try to get the class wide policy
        // from a.b.c.A$B$C, then a.b.c.A$B, and then a.b.c.A.
        while (true) {
            // Sometimes a class name has a `$` in it but not as a nest class name separator --
            // e.g. class name like "MyClass$$". In this case, `MyClass$` may not actually be
            // a class name.
            // So before getting the class policy on a nonexistent class, which may cause an
            // incorrect result, we make sure if className actually exists.
            if (classes.hasClass(className)) {
                outermostFilter.getPolicyForClass(className).let { policy ->
                    if (policy.policy.isClassWidePolicy) {
                    val p = if (resolve) policy.policy.resolveClassWidePolicy() else policy.policy
                        val p = if (resolve) {
                            policy.policy.resolveClassWidePolicy()
                        } else {
                            policy.policy
                        }

                    return p.withReason(policy.reason).wrapReason("class-wide in $currentClass")
                        return p.withReason(policy.reason)
                            .wrapReason("class-wide in $currentClass")
                    }
                    // If the class's policy is remove, then remove it.
                    if (policy.policy == FilterPolicy.Remove) {
                        return FilterPolicy.Remove.withReason("class-wide in $currentClass")
                    }
                }
            }

            // Next, look at the outer class...
            val outer = getDirectOuterClassName(currentClass)
+34 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.hoststubgen.utils

import com.android.hoststubgen.asm.getDirectOuterClassName
import com.google.common.truth.Truth.assertThat
import org.junit.Test

class AsmUtilsTest {
    private fun checkGetDirectOuterClassName(input: String, expected: String?) {
        assertThat(getDirectOuterClassName(input)).isEqualTo(expected)
    }

    @Test
    fun testGetDirectOuterClassName() {
        checkGetDirectOuterClassName("a", null)
        checkGetDirectOuterClassName("a\$x", "a")
        checkGetDirectOuterClassName("a.b.c\$x", "a.b.c")
        checkGetDirectOuterClassName("a.b.c\$x\$y", "a.b.c\$x")
    }
}
 No newline at end of file