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

Commit f1516fa7 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[hoststubgen] Add new `package` directive for text policy" into main

parents ad39ff33 5e33adbf
Loading
Loading
Loading
Loading
+61 −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.android.hoststubgen.filters

import com.android.hoststubgen.asm.toHumanReadableClassName
import com.android.hoststubgen.utils.Trie

/**
 * Filter to apply a policy to classes inside a package, either directly or indirectly.
 */
class PackageFilter(
    fallback: OutputFilter
) : DelegatingFilter(fallback) {

    private val mPackagePolicies = PackagePolicyTrie()

    // We want to pick the most specific filter for a package name.
    // Since any package with a matching prefix is a valid match, we can use a prefix tree
    // to help us find the nearest matching filter.
    private class PackagePolicyTrie : Trie<String, String, FilterPolicyWithReason>() {
        // Split package name into individual component
        override fun splitToComponents(key: String): Iterator<String> {
            return key.split('.').iterator()
        }
    }

    private fun getPackageKey(packageName: String): String {
        return packageName.toHumanReadableClassName()
    }

    private fun getPackageKeyFromClass(className: String): String {
        val clazz = className.toHumanReadableClassName()
        val idx = clazz.lastIndexOf('.')
        return if (idx >= 0) clazz.substring(0, idx) else ""
    }

    /**
     * Add a policy to all classes inside a package, either directly or indirectly.
     */
    fun addPolicy(packageName: String, policy: FilterPolicyWithReason) {
        mPackagePolicies[getPackageKey(packageName)] = policy
    }

    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
        return mPackagePolicies[getPackageKeyFromClass(className)]
            ?: super.getPolicyForClass(className)
    }
}
+28 −5
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ fun createFilterFromTextPolicyFile(
    log.i("Loading offloaded annotations from $filename ...")
    log.withIndent {
        val subclassFilter = SubclassFilter(classes, fallback)
        val imf = InMemoryOutputFilter(classes, subclassFilter)
        val packageFilter = PackageFilter(subclassFilter)
        val imf = InMemoryOutputFilter(classes, packageFilter)

        var lineNo = 0

@@ -78,10 +79,7 @@ fun createFilterFromTextPolicyFile(
                var className = ""

                while (true) {
                    var line = reader.readLine()
                    if (line == null) {
                        break
                    }
                    var line = reader.readLine() ?: break
                    lineNo++

                    line = normalizeTextLine(line)
@@ -95,6 +93,31 @@ fun createFilterFromTextPolicyFile(

                    val fields = line.split(whitespaceRegex).toTypedArray()
                    when (fields[0].lowercase()) {
                        "p", "package" -> {
                            if (fields.size < 3) {
                                throw ParseException("Package ('p') expects 2 fields.")
                            }
                            val name = fields[1]
                            val rawPolicy = fields[2]
                            if (resolveExtendingClass(name) != null) {
                                throw ParseException("Package can't be a super class type")
                            }
                            if (resolveSpecialClass(name) != SpecialClass.NotSpecial) {
                                throw ParseException("Package can't be a special class type")
                            }
                            if (rawPolicy.startsWith("!")) {
                                throw ParseException("Package can't have a substitution")
                            }
                            if (rawPolicy.startsWith("~")) {
                                throw ParseException("Package can't have a class load hook")
                            }
                            val policy = parsePolicy(rawPolicy)
                            if (!policy.isUsableWithClasses) {
                                throw ParseException("Package can't have policy '$policy'")
                            }
                            packageFilter.addPolicy(name, policy.withReason(FILTER_REASON))
                        }

                        "c", "class" -> {
                            if (fields.size < 3) {
                                throw ParseException("Class ('c') expects 2 fields.")
+58 −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.android.hoststubgen.utils

abstract class Trie<Key, Component, Value> {

    private val root = TrieNode<Component, Value>()

    abstract fun splitToComponents(key: Key): Iterator<Component>

    operator fun set(key: Key, value: Value) {
        val node = root.getExactNode(splitToComponents(key))
        node.value = value
    }

    operator fun get(key: Key): Value? {
        return root.getNearestValue(null, splitToComponents(key))
    }

    private class TrieNode<Component, Value> {
        private val children = mutableMapOf<Component, TrieNode<Component, Value>>()
        var value: Value? = null

        fun getExactNode(components: Iterator<Component>): TrieNode<Component, Value> {
            val n = components.next()
            val child = children.getOrPut(n) { TrieNode() }
            return if (components.hasNext()) {
                child.getExactNode(components)
            } else {
                child
            }
        }

        fun getNearestValue(current: Value?, components: Iterator<Component>): Value? {
            val n = components.next()
            val child = children[n] ?: return current
            val newValue = child.value ?: current
            return if (components.hasNext()) {
                child.getNearestValue(newValue, components)
            } else {
                newValue
            }
        }
    }
}
+92 −0
Original line number Diff line number Diff line
@@ -2706,6 +2706,98 @@ SourceFile: "TinyFrameworkPackageRedirect.java"
RuntimeInvisibleAnnotations:
  x: #x()
    android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
  Compiled from "A.java"
public class com.android.hoststubgen.test.tinyframework.packagetest.A
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/A
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 1, attributes: 1
  public com.android.hoststubgen.test.tinyframework.packagetest.A();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         x: aload_0
         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
         x: return
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/A;
}
SourceFile: "A.java"
## Class: com/android/hoststubgen/test/tinyframework/packagetest/B.class
  Compiled from "B.java"
public class com.android.hoststubgen.test.tinyframework.packagetest.B
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/B
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 1, attributes: 1
  public com.android.hoststubgen.test.tinyframework.packagetest.B();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         x: aload_0
         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
         x: return
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/B;
}
SourceFile: "B.java"
## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
  Compiled from "A.java"
public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 1, attributes: 1
  public com.android.hoststubgen.test.tinyframework.packagetest.sub.A();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         x: aload_0
         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
         x: return
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/A;
}
SourceFile: "A.java"
## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/B.class
  Compiled from "B.java"
public class com.android.hoststubgen.test.tinyframework.packagetest.sub.B
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/B
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 1, attributes: 1
  public com.android.hoststubgen.test.tinyframework.packagetest.sub.B();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         x: aload_0
         x: invokespecial #x                  // Method java/lang/Object."<init>":()V
         x: return
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/android/hoststubgen/test/tinyframework/packagetest/sub/B;
}
SourceFile: "B.java"
## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
  Compiled from "C1.java"
public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
+32 −0
Original line number Diff line number Diff line
@@ -2177,6 +2177,38 @@ RuntimeVisibleAnnotations:
RuntimeInvisibleAnnotations:
  x: #x()
    android.hosttest.annotation.HostSideTestWholeClassStub
## Class: com/android/hoststubgen/test/tinyframework/packagetest/A.class
  Compiled from "A.java"
public class com.android.hoststubgen.test.tinyframework.packagetest.A
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/A
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 0, attributes: 2
}
SourceFile: "A.java"
RuntimeVisibleAnnotations:
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
## Class: com/android/hoststubgen/test/tinyframework/packagetest/sub/A.class
  Compiled from "A.java"
public class com.android.hoststubgen.test.tinyframework.packagetest.sub.A
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/packagetest/sub/A
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 0, attributes: 2
}
SourceFile: "A.java"
RuntimeVisibleAnnotations:
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenKeptInStub
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl
## Class: com/android/hoststubgen/test/tinyframework/subclasstest/C1.class
  Compiled from "C1.java"
public class com.android.hoststubgen.test.tinyframework.subclasstest.C1
Loading