diff options
9 files changed, 20 insertions, 698 deletions
diff --git a/packages/SystemUI/plugin/Android.bp b/packages/SystemUI/plugin/Android.bp index a26cf1232636..682a68fdf846 100644 --- a/packages/SystemUI/plugin/Android.bp +++ b/packages/SystemUI/plugin/Android.bp @@ -23,7 +23,9 @@ package { } java_library { + name: "SystemUIPluginLib", + srcs: [ "bcsmartspace/src/**/*.java", "bcsmartspace/src/**/*.kt", @@ -38,8 +40,6 @@ java_library { 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 @@ java_library { "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 6d27b6f9637b..8dc4815b6f57 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 androidx.constraintlayout.widget.ConstraintSet 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 @@ import org.json.JSONObject 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 ClockProviderPlugin : Plugin, ClockProvider { } /** 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 ClockController { } /** 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 ClockMessageBuffers( 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 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout { } /** 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 @@ data class ClockReactiveSetting( ) /** Methods which trigger various clock animations */ -@ProtectedInterface interface ClockAnimations { /** Runs an enter animation (if any) */ fun enter() @@ -263,7 +230,6 @@ interface ClockAnimations { } /** Events that have specific data about the related face */ -@ProtectedInterface interface ClockFaceEvents { /** Call every time tick */ fun onTimeTick() @@ -304,9 +270,7 @@ enum class ClockTickRate(val value: Int) { /** 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 @@ data class ClockConfig( /** 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 31fbda557279..521c019d74f3 100644 --- a/packages/SystemUI/plugin_core/Android.bp +++ b/packages/SystemUI/plugin_core/Android.bp @@ -24,42 +24,8 @@ package { 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 @@ java_library { // 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 84040f984ec5..8ff6c114dded 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 @@ package com.android.systemui.plugins; import android.content.Context; -import com.android.systemui.plugins.annotations.ProtectedReturn; import com.android.systemui.plugins.annotations.Requires; /** @@ -117,8 +116,6 @@ public interface Plugin { * @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 425d00abb899..000000000000 --- 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 12a977d9350e..000000000000 --- 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 8266de54d557..000000000000 --- 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 941b2c2db4c1..000000000000 --- 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 5a9e0215d71a..87cc86f18fdc 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.Plugin; 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 @@ import java.util.function.Supplier; * * @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 @@ public class PluginInstance<T extends Plugin> 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 @@ public class PluginInstance<T extends Plugin> return mTag; } - /** */ - public boolean hasError() { - return mHasError; - } - public void setLogFunc(BiConsumer logConsumer) { mLogConsumer = logConsumer; } @@ -106,21 +97,8 @@ public class PluginInstance<T extends Plugin> } } - @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 @@ public class PluginInstance<T extends Plugin> /** 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 @@ public class PluginInstance<T extends Plugin> /** 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 @@ public class PluginInstance<T extends Plugin> } /** 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 @@ public class PluginInstance<T extends Plugin> /** 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); |