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

Commit b3fc530f authored by Makoto Onuki's avatar Makoto Onuki Committed by Android (Google) Code Review
Browse files

Merge "HostStubGen: Add heuristics for AIDL classes" into main

parents d43ef9e8 ac1422f0
Loading
Loading
Loading
Loading
+20 −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.asm

import com.android.hoststubgen.ClassParseException
@@ -40,6 +55,11 @@ class ClassNodes {
        return findClass(name) ?: throw ClassParseException("Class $name not found")
    }

    /** @return whether a class exists or not */
    fun hasClass(name: String): Boolean {
        return mAllClasses.containsKey(name.toJvmClassName())
    }

    /** Find a field, which may not exist. */
    fun findField(
            className: String,
+43 −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.filters

import com.android.hoststubgen.asm.ClassNodes

/**
 * Filter that deals with Android specific heuristics.
 */
class AndroidHeuristicsFilter(
        private val classes: ClassNodes,
        val aidlPolicy: FilterPolicyWithReason?,
        fallback: OutputFilter
) : DelegatingFilter(fallback) {
    override fun getPolicyForClass(className: String): FilterPolicyWithReason {
        if (aidlPolicy != null && classes.isAidlClass(className)) {
            return aidlPolicy
        }
        return super.getPolicyForClass(className)
    }
}

/**
 * @return if a given class "seems like" an AIDL (top-level) class.
 */
private fun ClassNodes.isAidlClass(className: String): Boolean {
    return hasClass(className) &&
            hasClass("$className\$Stub") &&
            hasClass("$className\$Proxy")
}
 No newline at end of file
+61 −9
Original line number Diff line number Diff line
@@ -58,10 +58,12 @@ fun createFilterFromTextPolicyFile(
        ): OutputFilter {
    log.i("Loading offloaded annotations from $filename ...")
    log.withIndent {
        val ret = InMemoryOutputFilter(classes, fallback)
        val imf = InMemoryOutputFilter(classes, fallback)

        var lineNo = 0

        var aidlPolicy: FilterPolicy? = null

        try {
            BufferedReader(FileReader(filename)).use { reader ->
                var className = ""
@@ -79,6 +81,9 @@ fun createFilterFromTextPolicyFile(
                        continue // skip empty lines.
                    }


                    // TODO: Method too long, break it up.

                    val fields = line.split(whitespaceRegex).toTypedArray()
                    when (fields[0].lowercase()) {
                        "c", "class" -> {
@@ -86,14 +91,27 @@ fun createFilterFromTextPolicyFile(
                                throw ParseException("Class ('c') expects 2 fields.")
                            }
                            className = fields[1]

                            val classType = resolveSpecialClass(className)

                            if (fields[2].startsWith("!")) {
                                if (classType != SpecialClass.NotSpecial) {
                                    // We could support it, but not needed at least for now.
                                    throw ParseException(
                                            "Special class can't have a substitution")
                                }
                                // It's a native-substitution.
                                val toClass = fields[2].substring(1)
                                ret.setNativeSubstitutionClass(className, toClass)
                                imf.setNativeSubstitutionClass(className, toClass)
                            } else if (fields[2].startsWith("~")) {
                                if (classType != SpecialClass.NotSpecial) {
                                    // We could support it, but not needed at least for now.
                                    throw ParseException(
                                            "Special class can't have a class load hook")
                                }
                                // It's a class-load hook
                                val callback = fields[2].substring(1)
                                ret.setClassLoadHook(className, callback)
                                imf.setClassLoadHook(className, callback)
                            } else {
                                val policy = parsePolicy(fields[2])
                                if (!policy.isUsableWithClasses) {
@@ -101,8 +119,20 @@ fun createFilterFromTextPolicyFile(
                                }
                                Objects.requireNonNull(className)

                                when (classType) {
                                    SpecialClass.NotSpecial -> {
                                        // TODO: Duplicate check, etc
                                ret.setPolicyForClass(className, policy.withReason(FILTER_REASON))
                                        imf.setPolicyForClass(
                                                className, policy.withReason(FILTER_REASON))
                                    }
                                    SpecialClass.Aidl -> {
                                        if (aidlPolicy != null) {
                                            throw ParseException(
                                                    "Policy for AIDL classes already defined")
                                        }
                                        aidlPolicy = policy
                                    }
                                }
                            }
                        }

@@ -118,7 +148,7 @@ fun createFilterFromTextPolicyFile(
                            Objects.requireNonNull(className)

                            // TODO: Duplicate check, etc
                            ret.setPolicyForField(className, name, policy.withReason(FILTER_REASON))
                            imf.setPolicyForField(className, name, policy.withReason(FILTER_REASON))
                        }

                        "m", "method" -> {
@@ -135,7 +165,7 @@ fun createFilterFromTextPolicyFile(

                            Objects.requireNonNull(className)

                            ret.setPolicyForMethod(className, name, signature,
                            imf.setPolicyForMethod(className, name, signature,
                                    policy.withReason(FILTER_REASON))
                            if (policy.isSubstitute) {
                                val fromName = fields[3].substring(1)
@@ -146,12 +176,12 @@ fun createFilterFromTextPolicyFile(
                                }

                                // Set the policy  for the "from" method.
                                ret.setPolicyForMethod(className, fromName, signature,
                                imf.setPolicyForMethod(className, fromName, signature,
                                        policy.getSubstitutionBasePolicy()
                                                .withReason(FILTER_REASON))

                                // Keep "from" -> "to" mapping.
                                ret.setRenameTo(className, fromName, signature, name)
                                imf.setRenameTo(className, fromName, signature, name)
                            }
                        }

@@ -164,10 +194,32 @@ fun createFilterFromTextPolicyFile(
        } catch (e: ParseException) {
            throw e.withSourceInfo(filename, lineNo)
        }

        var ret: OutputFilter = imf
        aidlPolicy?.let { policy ->
            log.d("AndroidHeuristicsFilter enabled")
            ret = AndroidHeuristicsFilter(
                    classes, policy.withReason("$FILTER_REASON (AIDL)"), imf)
        }
        return ret
    }
}

private enum class SpecialClass {
    NotSpecial,
    Aidl,
}

private fun resolveSpecialClass(className: String): SpecialClass {
    if (!className.startsWith(":")) {
        return SpecialClass.NotSpecial
    }
    when (className.lowercase()) {
        ":aidl" -> return SpecialClass.Aidl
    }
    throw ParseException("Invalid special class name \"$className\"")
}

private fun parsePolicy(s: String): FilterPolicy {
    return when (s.lowercase()) {
        "s", "stub" -> FilterPolicy.Stub
+97 −0
Original line number Diff line number Diff line
@@ -223,6 +223,103 @@ RuntimeVisibleAnnotations:
    java.lang.annotation.Target(
      value=[Ljava/lang/annotation/ElementType;.TYPE,Ljava/lang/annotation/ElementType;.FIELD,Ljava/lang/annotation/ElementType;.METHOD]
    )
## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
  Compiled from "IPretendingAidl.java"
public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 3
  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
    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/IPretendingAidl$Proxy;

  public static int addTwo(int);
    descriptor: (I)I
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         x: iload_0
         x: iconst_2
         x: iadd
         x: ireturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0     a   I
}
SourceFile: "IPretendingAidl.java"
NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
InnerClasses:
  public static #x= #x of #x;           // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
  Compiled from "IPretendingAidl.java"
public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 3
  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
    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/IPretendingAidl$Stub;

  public static int addOne(int);
    descriptor: (I)I
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         x: iload_0
         x: iconst_1
         x: iadd
         x: ireturn
      LineNumberTable:
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0     a   I
}
SourceFile: "IPretendingAidl.java"
NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
InnerClasses:
  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
  Compiled from "IPretendingAidl.java"
public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
  minor version: 0
  major version: 61
  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 0, attributes: 3
}
SourceFile: "IPretendingAidl.java"
NestMembers:
  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
InnerClasses:
  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
  Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
+102 −0
Original line number Diff line number Diff line
## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy.class
  Compiled from "IPretendingAidl.java"
public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 4
  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Proxy();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         x: new           #x                 // class java/lang/RuntimeException
         x: dup
         x: ldc           #x                 // String Stub!
         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
         x: athrow

  public static int addTwo(int);
    descriptor: (I)I
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         x: new           #x                 // class java/lang/RuntimeException
         x: dup
         x: ldc           #x                 // String Stub!
         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
         x: athrow
}
InnerClasses:
  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
SourceFile: "IPretendingAidl.java"
RuntimeVisibleAnnotations:
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub.class
  Compiled from "IPretendingAidl.java"
public class com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub
  minor version: 0
  major version: 61
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 4
  public com.android.hoststubgen.test.tinyframework.IPretendingAidl$Stub();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         x: new           #x                 // class java/lang/RuntimeException
         x: dup
         x: ldc           #x                 // String Stub!
         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
         x: athrow

  public static int addOne(int);
    descriptor: (I)I
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         x: new           #x                 // class java/lang/RuntimeException
         x: dup
         x: ldc           #x                 // String Stub!
         x: invokespecial #x                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
         x: athrow
}
InnerClasses:
  public static #x= #x of #x;            // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
SourceFile: "IPretendingAidl.java"
RuntimeVisibleAnnotations:
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestHost: class com/android/hoststubgen/test/tinyframework/IPretendingAidl
## Class: com/android/hoststubgen/test/tinyframework/IPretendingAidl.class
  Compiled from "IPretendingAidl.java"
public interface com.android.hoststubgen.test.tinyframework.IPretendingAidl
  minor version: 0
  major version: 61
  flags: (0x0601) ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
  this_class: #x                          // com/android/hoststubgen/test/tinyframework/IPretendingAidl
  super_class: #x                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 0, attributes: 4
}
InnerClasses:
  public static #x= #x of #x;            // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
  public static #x= #x of #x;           // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl
SourceFile: "IPretendingAidl.java"
RuntimeVisibleAnnotations:
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedStubClass
  x: #x()
    com.android.hoststubgen.hosthelper.HostStubGenProcessedKeepClass
NestMembers:
  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Proxy
  com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub
## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class
  Compiled from "TinyFrameworkCallerCheck.java"
class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl
Loading