1 /* <lambda>null2 * Copyright (C) 2023 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 package com.android.hoststubgen.filters 17 18 import com.android.hoststubgen.HostStubGenErrors 19 import com.android.hoststubgen.asm.ClassNodes 20 21 private const val REASON = "demoted, not in intersect jars" 22 23 /** 24 * An [OutputFilter] that will restrict what to put in stub to only what shows up in "intersecting 25 * jar" files. 26 * 27 * For example, if the Android public API stub jar is provided, then the HostStubGen's output 28 * stub will be restricted to public APIs. 29 */ 30 class StubIntersectingFilter( 31 private val errors: HostStubGenErrors, 32 /** 33 * If a class / field / method is not in any of these jars, then we will not put it in 34 * stub. 35 */ 36 private val intersectingJars: Map<String, ClassNodes>, 37 fallback: OutputFilter, 38 ) : DelegatingFilter(fallback) { 39 private inline fun exists(predicate: (ClassNodes) -> Boolean): Boolean { 40 intersectingJars.forEach { entry -> 41 if (predicate(entry.value)) { 42 return true 43 } 44 } 45 return false 46 } 47 48 /** 49 * If [origPolicy] is less than "Stub", then return it as-is. 50 * 51 * Otherwise, call [inStubChecker] to see if the API is in any of [intersectingJars]. 52 * If yes, then return [origPolicy] as-is. Otherwise, demote to "Keep". 53 */ 54 private fun intersectWithStub( 55 origPolicy: FilterPolicyWithReason, 56 inStubChecker: () -> Boolean, 57 ): FilterPolicyWithReason { 58 if (origPolicy.policy.needsInStub) { 59 // Only check the stub jars, when the class is supposed to be in stub otherwise. 60 if (!inStubChecker()) { 61 return origPolicy.demoteToKeep(REASON) 62 } 63 } 64 return origPolicy 65 } 66 67 override fun getPolicyForClass(className: String): FilterPolicyWithReason { 68 return intersectWithStub(super.getPolicyForClass(className)) { 69 exists { classes -> classes.findClass(className) != null } 70 } 71 } 72 73 override fun getPolicyForField( 74 className: String, 75 fieldName: String 76 ): FilterPolicyWithReason { 77 return intersectWithStub(super.getPolicyForField(className, fieldName)) { 78 exists { classes -> classes.findField(className, fieldName) != null } 79 } 80 } 81 82 override fun getPolicyForMethod( 83 className: String, 84 methodName: String, 85 descriptor: String 86 ): FilterPolicyWithReason { 87 return intersectWithStub(super.getPolicyForMethod(className, methodName, descriptor)) { 88 exists { classes -> classes.findMethod(className, methodName, descriptor) != null } 89 } 90 } 91 }