Revert "Use codegen to catch LinkageErrors from plugins"
Revert submission 28801121-codegen-plugin
Reason for revert: Droidmonitor created revert due to b/368040334.
Reverted changes: /q/submissionid:28801121-codegen-plugin
Change-Id: I7888264372acdbb7352f80317926aab84be140da
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp
index a26cf12..682a68f 100644
--- a/packages/SystemUI/plugin/Android.bp
+++ b/packages/SystemUI/plugin/Android.bp
@@ -23,7 +23,9 @@
}
java_library {
+
name: "SystemUIPluginLib",
+
srcs: [
"bcsmartspace/src/**/*.java",
"bcsmartspace/src/**/*.kt",
@@ -38,8 +40,6 @@
export_proguard_flags_files: true,
},
- plugins: ["PluginAnnotationProcessor"],
-
// If you add a static lib here, you may need to also add the package to the ClassLoaderFilter
// in PluginInstance. That will ensure that loaded plugins have access to the related classes.
// You should also add it to proguard_common.flags so that proguard does not remove the portions
@@ -53,6 +53,7 @@
"SystemUILogLib",
"androidx.annotation_annotation",
],
+
}
android_app {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
index 6d27b6f..8dc4815 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt
@@ -21,11 +21,7 @@
import com.android.internal.annotations.Keep
import com.android.systemui.log.core.MessageBuffer
import com.android.systemui.plugins.Plugin
-import com.android.systemui.plugins.annotations.GeneratedImport
-import com.android.systemui.plugins.annotations.ProtectedInterface
-import com.android.systemui.plugins.annotations.ProtectedReturn
import com.android.systemui.plugins.annotations.ProvidesInterface
-import com.android.systemui.plugins.annotations.SimpleProperty
import java.io.PrintWriter
import java.util.Locale
import java.util.TimeZone
@@ -35,7 +31,6 @@
typealias ClockId = String
/** A Plugin which exposes the ClockProvider interface */
-@ProtectedInterface
@ProvidesInterface(action = ClockProviderPlugin.ACTION, version = ClockProviderPlugin.VERSION)
interface ClockProviderPlugin : Plugin, ClockProvider {
companion object {
@@ -45,42 +40,31 @@
}
/** Interface for building clocks and providing information about those clocks */
-@ProtectedInterface
-@GeneratedImport("java.util.List")
-@GeneratedImport("java.util.ArrayList")
interface ClockProvider {
/** Initializes the clock provider with debug log buffers */
fun initialize(buffers: ClockMessageBuffers?)
- @ProtectedReturn("return new ArrayList<ClockMetadata>();")
/** Returns metadata for all clocks this provider knows about */
fun getClocks(): List<ClockMetadata>
- @ProtectedReturn("return null;")
/** Initializes and returns the target clock design */
- fun createClock(settings: ClockSettings): ClockController?
+ fun createClock(settings: ClockSettings): ClockController
- @ProtectedReturn("return new ClockPickerConfig(\"\", \"\", \"\", null);")
/** Settings configuration parameters for the clock */
fun getClockPickerConfig(id: ClockId): ClockPickerConfig
}
/** Interface for controlling an active clock */
-@ProtectedInterface
interface ClockController {
- @get:SimpleProperty
/** A small version of the clock, appropriate for smaller viewports */
val smallClock: ClockFaceController
- @get:SimpleProperty
/** A large version of the clock, appropriate when a bigger viewport is available */
val largeClock: ClockFaceController
- @get:SimpleProperty
/** Determines the way the hosting app should behave when rendering either clock face */
val config: ClockConfig
- @get:SimpleProperty
/** Events that clocks may need to respond to */
val events: ClockEvents
@@ -92,26 +76,19 @@
}
/** Interface for a specific clock face version rendered by the clock */
-@ProtectedInterface
interface ClockFaceController {
- @get:SimpleProperty
- @Deprecated("Prefer use of layout")
/** View that renders the clock face */
val view: View
- @get:SimpleProperty
/** Layout specification for this clock */
val layout: ClockFaceLayout
- @get:SimpleProperty
/** Determines the way the hosting app should behave when rendering this clock face */
val config: ClockFaceConfig
- @get:SimpleProperty
/** Events specific to this clock face */
val events: ClockFaceEvents
- @get:SimpleProperty
/** Triggers for various animations */
val animations: ClockAnimations
}
@@ -130,21 +107,14 @@
data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float)
-/** Specifies layout information for the clock face */
-@ProtectedInterface
-@GeneratedImport("java.util.ArrayList")
-@GeneratedImport("android.view.View")
+/** Specifies layout information for the */
interface ClockFaceLayout {
- @get:ProtectedReturn("return new ArrayList<View>();")
/** All clock views to add to the root constraint layout before applying constraints. */
val views: List<View>
- @ProtectedReturn("return constraints;")
/** Custom constraints to apply to Lockscreen ConstraintLayout. */
fun applyConstraints(constraints: ConstraintSet): ConstraintSet
- @ProtectedReturn("return constraints;")
- /** Custom constraints to apply to preview ConstraintLayout. */
fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet
fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel)
@@ -175,9 +145,7 @@
}
/** Events that should call when various rendering parameters change */
-@ProtectedInterface
interface ClockEvents {
- @get:ProtectedReturn("return false;")
/** Set to enable or disable swipe interaction */
var isReactiveTouchInteractionEnabled: Boolean
@@ -219,7 +187,6 @@
)
/** Methods which trigger various clock animations */
-@ProtectedInterface
interface ClockAnimations {
/** Runs an enter animation (if any) */
fun enter()
@@ -263,7 +230,6 @@
}
/** Events that have specific data about the related face */
-@ProtectedInterface
interface ClockFaceEvents {
/** Call every time tick */
fun onTimeTick()
@@ -304,9 +270,7 @@
/** Some data about a clock design */
data class ClockMetadata(val clockId: ClockId)
-data class ClockPickerConfig
-@JvmOverloads
-constructor(
+data class ClockPickerConfig(
val id: String,
/** Localized name of the clock */
@@ -374,7 +338,7 @@
/** Transition to AOD should move smartspace like large clock instead of small clock */
val useAlternateSmartspaceAODTransition: Boolean = false,
- /** Deprecated version of isReactiveToTone; moved to ClockPickerConfig */
+ /** Use ClockPickerConfig.isReactiveToTone instead */
@Deprecated("TODO(b/352049256): Remove in favor of ClockPickerConfig.isReactiveToTone")
val isReactiveToTone: Boolean = true,
diff --git a/packages/SystemUI/plugin_core/Android.bp b/packages/SystemUI/plugin_core/Android.bp
index 31fbda5..521c019 100644
--- a/packages/SystemUI/plugin_core/Android.bp
+++ b/packages/SystemUI/plugin_core/Android.bp
@@ -24,42 +24,8 @@
java_library {
sdk_version: "current",
- name: "PluginAnnotationLib",
- host_supported: true,
- device_supported: true,
- srcs: [
- "src/**/annotations/*.java",
- "src/**/annotations/*.kt",
- ],
- optimize: {
- proguard_flags_files: ["proguard.flags"],
- // Ensure downstream clients that reference this as a shared lib
- // inherit the appropriate flags to preserve annotations.
- export_proguard_flags_files: true,
- },
-
- // Enforce that the library is built against java 8 so that there are
- // no compatibility issues with launcher
- java_version: "1.8",
-}
-
-java_library {
- sdk_version: "current",
name: "PluginCoreLib",
- device_supported: true,
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- exclude_srcs: [
- "src/**/annotations/*.java",
- "src/**/annotations/*.kt",
- "src/**/processor/*.java",
- "src/**/processor/*.kt",
- ],
- static_libs: [
- "PluginAnnotationLib",
- ],
+ srcs: ["src/**/*.java"],
optimize: {
proguard_flags_files: ["proguard.flags"],
// Ensure downstream clients that reference this as a shared lib
@@ -71,30 +37,3 @@
// no compatibility issues with launcher
java_version: "1.8",
}
-
-java_library {
- java_version: "1.8",
- name: "PluginAnnotationProcessorLib",
- host_supported: true,
- device_supported: false,
- srcs: [
- "src/**/processor/*.java",
- "src/**/processor/*.kt",
- ],
- plugins: ["auto_service_plugin"],
- static_libs: [
- "androidx.annotation_annotation",
- "auto_service_annotations",
- "auto_common",
- "PluginAnnotationLib",
- "guava",
- "jsr330",
- ],
-}
-
-java_plugin {
- name: "PluginAnnotationProcessor",
- processor_class: "com.android.systemui.plugins.processor.ProtectedPluginProcessor",
- static_libs: ["PluginAnnotationProcessorLib"],
- java_version: "1.8",
-}
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java
index 84040f9..8ff6c11 100644
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java
+++ b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/Plugin.java
@@ -15,7 +15,6 @@
import android.content.Context;
-import com.android.systemui.plugins.annotations.ProtectedReturn;
import com.android.systemui.plugins.annotations.Requires;
/**
@@ -117,8 +116,6 @@
* @deprecated
* @see Requires
*/
- @Deprecated
- @ProtectedReturn(statement = "return -1;")
default int getVersion() {
// Default of -1 indicates the plugin supports the new Requires model.
return -1;
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt
deleted file mode 100644
index 425d00a..0000000
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/ProtectedPluginListener.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.systemui.plugins
-
-/** Listener for events from proxy types generated by [ProtectedPluginProcessor]. */
-interface ProtectedPluginListener {
- /**
- * Called when a method call produces a [LinkageError] before returning. This callback is
- * provided so that the host application can terminate the plugin or log the error as
- * appropraite.
- *
- * @return true to terminate all methods within this object; false if the error is recoverable
- * and the proxied plugin should continue to operate as normal.
- */
- fun onFail(className: String, methodName: String, failure: LinkageError): Boolean
-}
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt
deleted file mode 100644
index 12a977d..0000000
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/annotations/ProtectedInterface.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.systemui.plugins.annotations
-
-/**
- * This annotation marks denotes that an interface should use a proxy layer to protect the plugin
- * host from crashing due to [LinkageError]s originating within the plugin's implementation.
- */
-@Target(AnnotationTarget.CLASS)
-@Retention(AnnotationRetention.BINARY)
-annotation class ProtectedInterface
-
-/**
- * This annotation specifies any additional imports that the processor will require when generating
- * the proxy implementation for the target interface. The interface in question must still be
- * annotated with [ProtectedInterface].
- */
-@Repeatable
-@Target(AnnotationTarget.CLASS)
-@Retention(AnnotationRetention.BINARY)
-annotation class GeneratedImport(val extraImport: String)
-
-/**
- * This annotation provides default values to return when the proxy implementation catches a
- * [LinkageError]. The string specified should be a simple but valid java statement. In most cases
- * it should be a return statement of the appropriate type, but in some cases throwing a known
- * exception type may be preferred.
- *
- * This annotation is not required for methods that return void, but will behave the same way.
- */
-@Target(
- AnnotationTarget.FUNCTION,
- AnnotationTarget.PROPERTY,
- AnnotationTarget.PROPERTY_GETTER,
- AnnotationTarget.PROPERTY_SETTER,
-)
-@Retention(AnnotationRetention.BINARY)
-annotation class ProtectedReturn(val statement: String)
-
-/**
- * Some very simple properties and methods need not be protected by the proxy implementation. This
- * annotation can be used to omit the normal try-catch wrapper the proxy is using. These members
- * will instead be a direct passthrough.
- *
- * It should only be used for members where the plugin implementation is expected to be exceedingly
- * simple. Any member marked with this annotation should be no more complex than kotlin's automatic
- * properties, and make no other method calls whatsoever.
- */
-@Target(
- AnnotationTarget.FUNCTION,
- AnnotationTarget.PROPERTY,
- AnnotationTarget.PROPERTY_GETTER,
- AnnotationTarget.PROPERTY_SETTER,
-)
-@Retention(AnnotationRetention.BINARY)
-annotation class SimpleProperty
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt
deleted file mode 100644
index 8266de5..0000000
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/ProtectedPluginProcessor.kt
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * 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.systemui.plugins.processor
-
-import com.android.systemui.plugins.annotations.GeneratedImport
-import com.android.systemui.plugins.annotations.ProtectedInterface
-import com.android.systemui.plugins.annotations.ProtectedReturn
-import com.android.systemui.plugins.annotations.SimpleProperty
-import com.google.auto.service.AutoService
-import javax.annotation.processing.AbstractProcessor
-import javax.annotation.processing.ProcessingEnvironment
-import javax.annotation.processing.RoundEnvironment
-import javax.lang.model.element.Element
-import javax.lang.model.element.ElementKind
-import javax.lang.model.element.ExecutableElement
-import javax.lang.model.element.PackageElement
-import javax.lang.model.element.TypeElement
-import javax.lang.model.type.TypeKind
-import javax.lang.model.type.TypeMirror
-import javax.tools.Diagnostic.Kind
-import kotlin.collections.ArrayDeque
-
-/**
- * [ProtectedPluginProcessor] generates a proxy implementation for interfaces annotated with
- * [ProtectedInterface] which catches [LinkageError]s generated by the proxied target. This protects
- * the plugin host from crashing due to out-of-date plugin code, where some call has changed so that
- * the [ClassLoader] can no longer resolve it correctly.
- *
- * [PluginInstance] observes these failures via [ProtectedMethodListener] and unloads the plugin in
- * question to prevent further issues. This persists through further load/unload requests.
- *
- * To centralize access to the proxy types, an additional type [PluginProtector] is also generated.
- * This class provides static methods which wrap an instance of the target interface in the proxy
- * type if it is not already an instance of the proxy.
- */
-@AutoService(ProtectedPluginProcessor::class)
-class ProtectedPluginProcessor : AbstractProcessor() {
- private lateinit var procEnv: ProcessingEnvironment
-
- override fun init(procEnv: ProcessingEnvironment) {
- this.procEnv = procEnv
- }
-
- override fun getSupportedAnnotationTypes(): Set<String> =
- setOf("com.android.systemui.plugins.annotations.ProtectedInterface")
-
- private data class TargetData(
- val attribute: TypeElement,
- val sourceType: Element,
- val sourcePkg: String,
- val sourceName: String,
- val outputName: String,
- )
-
- override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
- val targets = mutableMapOf<String, TargetData>() // keyed by fully-qualified source name
- val additionalImports = mutableSetOf<String>()
- for (attr in annotations) {
- for (target in roundEnv.getElementsAnnotatedWith(attr)) {
- val sourceName = "${target.simpleName}"
- val outputName = "${sourceName}Protector"
- val pkg = (target.getEnclosingElement() as PackageElement).qualifiedName.toString()
- targets.put("$target", TargetData(attr, target, pkg, sourceName, outputName))
-
- // This creates excessive imports, but it should be fine
- additionalImports.add("$pkg.$sourceName")
- additionalImports.add("$pkg.$outputName")
- }
- }
-
- if (targets.size <= 0) return false
- for ((_, sourceType, sourcePkg, sourceName, outputName) in targets.values) {
- // Find all methods in this type and all super types to that need to be implemented
- val types = ArrayDeque<TypeMirror>().apply { addLast(sourceType.asType()) }
- val impAttrs = mutableListOf<GeneratedImport>()
- val methods = mutableListOf<ExecutableElement>()
- while (types.size > 0) {
- val typeMirror = types.removeLast()
- if (typeMirror.toString() == "java.lang.Object") continue
- val type = procEnv.typeUtils.asElement(typeMirror)
- for (member in type.enclosedElements) {
- if (member.kind != ElementKind.METHOD) continue
- methods.add(member as ExecutableElement)
- }
-
- impAttrs.addAll(type.getAnnotationsByType(GeneratedImport::class.java))
- types.addAll(procEnv.typeUtils.directSupertypes(typeMirror))
- }
-
- val file = procEnv.filer.createSourceFile("$outputName")
- TabbedWriter.writeTo(file.openWriter()) {
- line("package $sourcePkg;")
- line()
-
- // Imports used by the proxy implementation
- line("import android.util.Log;")
- line("import java.lang.LinkageError;")
- line("import com.android.systemui.plugins.ProtectedPluginListener;")
- line()
-
- // Imports of other generated types
- if (additionalImports.size > 0) {
- for (impTarget in additionalImports) {
- line("import $impTarget;")
- }
- line()
- }
-
- // Imports declared via @GeneratedImport
- if (impAttrs.size > 0) {
- for (impAttr in impAttrs) {
- line("import ${impAttr.extraImport};")
- }
- line()
- }
-
- braceBlock("public class $outputName implements $sourceName") {
- line("private static final String CLASS = \"$sourceName\";")
-
- // Static factory method to prevent wrapping the same object twice
- parenBlock("public static $outputName protect") {
- line("$sourceName instance,")
- line("ProtectedPluginListener listener")
- }
- braceBlock {
- line("if (instance instanceof $outputName)")
- line(" return ($outputName)instance;")
- line("return new $outputName(instance, listener);")
- }
- line()
-
- // Member Fields
- line("private $sourceName mInstance;")
- line("private ProtectedPluginListener mListener;")
- line("private boolean mHasError = false;")
- line()
-
- // Constructor
- parenBlock("private $outputName") {
- line("$sourceName instance,")
- line("ProtectedPluginListener listener")
- }
- braceBlock {
- line("mInstance = instance;")
- line("mListener = listener;")
- }
- line()
-
- // Method implementations
- for (method in methods) {
- val methodName = method.simpleName
- val returnTypeName = method.returnType.toString()
- val callArgs = StringBuilder()
- var isFirst = true
-
- line("@Override")
- parenBlock("public $returnTypeName $methodName") {
- // While copying the method signature for the proxy type, we also
- // accumulate arguments for the nested callsite.
- for (param in method.parameters) {
- if (!isFirst) completeLine(",")
- startLine("${param.asType()} ${param.simpleName}")
- isFirst = false
-
- if (callArgs.length > 0) callArgs.append(", ")
- callArgs.append(param.simpleName)
- }
- }
-
- val isVoid = method.returnType.kind == TypeKind.VOID
- val nestedCall = "mInstance.$methodName($callArgs)"
- val callStatement =
- when {
- isVoid -> "$nestedCall;"
- targets.containsKey(returnTypeName) -> {
- val targetType = targets.get(returnTypeName)!!.outputName
- "return $targetType.protect($nestedCall, mListener);"
- }
- else -> "return $nestedCall;"
- }
-
- // Simple property methods forgo protection
- val simpleAttr = method.getAnnotation(SimpleProperty::class.java)
- if (simpleAttr != null) {
- braceBlock {
- line("final String METHOD = \"$methodName\";")
- line(callStatement)
- }
- line()
- continue
- }
-
- // Standard implementation wraps nested call in try-catch
- braceBlock {
- val retAttr = method.getAnnotation(ProtectedReturn::class.java)
- val errorStatement =
- when {
- retAttr != null -> retAttr.statement
- isVoid -> "return;"
- else -> {
- // Non-void methods must be annotated.
- procEnv.messager.printMessage(
- Kind.ERROR,
- "$outputName.$methodName must be annotated with " +
- "@ProtectedReturn or @SimpleProperty",
- )
- "throw ex;"
- }
- }
-
- line("final String METHOD = \"$methodName\";")
-
- // Return immediately if any previous call has failed.
- braceBlock("if (mHasError)") { line(errorStatement) }
-
- // Protect callsite in try/catch block
- braceBlock("try") { line(callStatement) }
-
- // Notify listener when a LinkageError is caught
- braceBlock("catch (LinkageError ex)") {
- line("Log.wtf(CLASS, \"Failed to execute: \" + METHOD, ex);")
- line("mHasError = mListener.onFail(CLASS, METHOD, ex);")
- line(errorStatement)
- }
- }
- line()
- }
- }
- }
- }
-
- // Write a centralized static factory type to its own file. This is for convience so that
- // PluginInstance need not resolve each generated type at runtime as plugins are loaded.
- val factoryFile = procEnv.filer.createSourceFile("PluginProtector")
- TabbedWriter.writeTo(factoryFile.openWriter()) {
- line("package com.android.systemui.plugins;")
- line()
-
- line("import java.util.Map;")
- line("import java.util.ArrayList;")
- line("import java.util.HashSet;")
- line("import static java.util.Map.entry;")
- line()
-
- for (impTarget in additionalImports) {
- line("import $impTarget;")
- }
- line()
-
- braceBlock("public final class PluginProtector") {
- line("private PluginProtector() { }")
- line()
-
- // Untyped factory SAM, private to this type.
- braceBlock("private interface Factory") {
- line("Object create(Object plugin, ProtectedPluginListener listener);")
- }
- line()
-
- // Store a reference to each `protect` method in a map by interface type.
- parenBlock("private static final Map<Class, Factory> sFactories = Map.ofEntries") {
- var isFirst = true
- for (target in targets.values) {
- if (!isFirst) completeLine(",")
- target.apply {
- startLine("entry($sourceName.class, ")
- appendLine("(p, h) -> $outputName.protect(($sourceName)p, h))")
- }
- isFirst = false
- }
- }
- completeLine(";")
- line()
-
- // Lookup the relevant factory based on the instance type, if not found return null.
- parenBlock("public static <T> T tryProtect") {
- line("T target,")
- line("ProtectedPluginListener listener")
- }
- braceBlock {
- // Accumulate interfaces from type and all base types
- line("HashSet<Class> interfaces = new HashSet<Class>();")
- line("Class current = target.getClass();")
- braceBlock("while (current != null)") {
- braceBlock("for (Class cls : current.getInterfaces())") {
- line("interfaces.add(cls);")
- }
- line("current = current.getSuperclass();")
- }
- line()
-
- // Check if any of the interfaces are marked protectable
- line("int candidateCount = 0;")
- line("Factory candidateFactory = null;")
- braceBlock("for (Class cls : interfaces)") {
- line("Factory factory = sFactories.get(cls);")
- braceBlock("if (factory != null)") {
- line("candidateFactory = factory;")
- line("candidateCount++;")
- }
- }
- line()
-
- // No match, return null
- braceBlock("if (candidateFactory == null)") { line("return null;") }
-
- // Multiple matches, not supported
- braceBlock("if (candidateCount >= 2)") {
- var error = "Plugin implements more than one protected interface"
- line("throw new UnsupportedOperationException(\"$error\");")
- }
-
- // Call the factory and wrap the target object
- line("return (T)candidateFactory.create(target, listener);")
- }
- line()
-
- // Wraps the target with the appropriate generated proxy if it exists.
- parenBlock("public static <T> T protectIfAble") {
- line("T target,")
- line("ProtectedPluginListener listener")
- }
- braceBlock {
- line("T result = tryProtect(target, listener);")
- line("return result != null ? result : target;")
- }
- line()
- }
- }
-
- return true
- }
-}
diff --git a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/TabbedWriter.kt b/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/TabbedWriter.kt
deleted file mode 100644
index 941b2c2..0000000
--- a/packages/SystemUI/plugin_core/src/com/android/systemui/plugins/processor/TabbedWriter.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.systemui.plugins.processor
-
-import java.io.BufferedWriter
-import java.io.Writer
-
-/**
- * [TabbedWriter] is a convience class which tracks and writes correctly tabbed lines for generating
- * source files. These files don't need to be correctly tabbed as they're ephemeral and not part of
- * the source tree, but correct tabbing makes debugging much easier when the build fails.
- */
-class TabbedWriter(writer: Writer) : AutoCloseable {
- private val target = BufferedWriter(writer)
- private var isInProgress = false
- var tabCount: Int = 0
- private set
-
- override fun close() = target.close()
-
- fun line() {
- target.newLine()
- isInProgress = false
- }
-
- fun line(str: String) {
- if (isInProgress) {
- target.newLine()
- }
-
- target.append(" ".repeat(tabCount))
- target.append(str)
- target.newLine()
- isInProgress = false
- }
-
- fun completeLine(str: String) {
- if (!isInProgress) {
- target.newLine()
- target.append(" ".repeat(tabCount))
- }
-
- target.append(str)
- target.newLine()
- isInProgress = false
- }
-
- fun startLine(str: String) {
- if (isInProgress) {
- target.newLine()
- }
-
- target.append(" ".repeat(tabCount))
- target.append(str)
- isInProgress = true
- }
-
- fun appendLine(str: String) {
- if (!isInProgress) {
- target.append(" ".repeat(tabCount))
- }
-
- target.append(str)
- isInProgress = true
- }
-
- fun braceBlock(str: String = "", write: TabbedWriter.() -> Unit) {
- block(str, " {", "}", true, write)
- }
-
- fun parenBlock(str: String = "", write: TabbedWriter.() -> Unit) {
- block(str, "(", ")", false, write)
- }
-
- private fun block(
- str: String,
- start: String,
- end: String,
- newLineForEnd: Boolean,
- write: TabbedWriter.() -> Unit,
- ) {
- appendLine(str)
- completeLine(start)
-
- tabCount++
- this.write()
- tabCount--
-
- if (newLineForEnd) {
- line(end)
- } else {
- startLine(end)
- }
- }
-
- companion object {
- fun writeTo(writer: Writer, write: TabbedWriter.() -> Unit) {
- TabbedWriter(writer).use { it.write() }
- }
- }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
index 5a9e021..87cc86f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginInstance.java
@@ -32,8 +32,6 @@
import com.android.systemui.plugins.PluginFragment;
import com.android.systemui.plugins.PluginLifecycleManager;
import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.PluginProtector;
-import com.android.systemui.plugins.ProtectedPluginListener;
import dalvik.system.PathClassLoader;
@@ -51,8 +49,7 @@
*
* @param <T> The type of plugin that this contains.
*/
-public class PluginInstance<T extends Plugin>
- implements PluginLifecycleManager, ProtectedPluginListener {
+public class PluginInstance<T extends Plugin> implements PluginLifecycleManager {
private static final String TAG = "PluginInstance";
private final Context mAppContext;
@@ -61,7 +58,6 @@
private final PluginFactory<T> mPluginFactory;
private final String mTag;
- private boolean mHasError = false;
private BiConsumer<String, String> mLogConsumer = null;
private Context mPluginContext;
private T mPlugin;
@@ -91,11 +87,6 @@
return mTag;
}
- /** */
- public boolean hasError() {
- return mHasError;
- }
-
public void setLogFunc(BiConsumer logConsumer) {
mLogConsumer = logConsumer;
}
@@ -106,21 +97,8 @@
}
}
- @Override
- public synchronized boolean onFail(String className, String methodName, LinkageError failure) {
- mHasError = true;
- unloadPlugin();
- mListener.onPluginDetached(this);
- return true;
- }
-
/** Alerts listener and plugin that the plugin has been created. */
public synchronized void onCreate() {
- if (mHasError) {
- log("Previous LinkageError detected for plugin class");
- return;
- }
-
boolean loadPlugin = mListener.onPluginAttached(this);
if (!loadPlugin) {
if (mPlugin != null) {
@@ -148,12 +126,6 @@
/** Alerts listener and plugin that the plugin is being shutdown. */
public synchronized void onDestroy() {
- if (mHasError) {
- // Detached in error handler
- log("onDestroy - no-op");
- return;
- }
-
log("onDestroy");
unloadPlugin();
mListener.onPluginDetached(this);
@@ -162,25 +134,20 @@
/** Returns the current plugin instance (if it is loaded). */
@Nullable
public T getPlugin() {
- return mHasError ? null : mPlugin;
+ return mPlugin;
}
/**
* Loads and creates the plugin if it does not exist.
*/
public synchronized void loadPlugin() {
- if (mHasError) {
- log("Previous LinkageError detected for plugin class");
- return;
- }
-
if (mPlugin != null) {
log("Load request when already loaded");
return;
}
// Both of these calls take about 1 - 1.5 seconds in test runs
- mPlugin = mPluginFactory.createPlugin(this);
+ mPlugin = mPluginFactory.createPlugin();
mPluginContext = mPluginFactory.createPluginContext();
if (mPlugin == null || mPluginContext == null) {
Log.e(mTag, "Requested load, but failed");
@@ -397,16 +364,20 @@
}
/** Creates the related plugin object from the factory */
- public T createPlugin(ProtectedPluginListener listener) {
+ public T createPlugin() {
try {
ClassLoader loader = mClassLoaderFactory.get();
Class<T> instanceClass = (Class<T>) Class.forName(
mComponentName.getClassName(), true, loader);
T result = (T) mInstanceFactory.create(instanceClass);
Log.v(TAG, "Created plugin: " + result);
- return PluginProtector.protectIfAble(result, listener);
- } catch (ReflectiveOperationException ex) {
- Log.wtf(TAG, "Failed to load plugin", ex);
+ return result;
+ } catch (ClassNotFoundException ex) {
+ Log.e(TAG, "Failed to load plugin", ex);
+ } catch (IllegalAccessException ex) {
+ Log.e(TAG, "Failed to load plugin", ex);
+ } catch (InstantiationException ex) {
+ Log.e(TAG, "Failed to load plugin", ex);
}
return null;
}
@@ -426,7 +397,7 @@
/** Check Version and create VersionInfo for instance */
public VersionInfo checkVersion(T instance) {
if (instance == null) {
- instance = createPlugin(null);
+ instance = createPlugin();
}
return mVersionChecker.checkVersion(
(Class<T>) instance.getClass(), mPluginClass, instance);