• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 
17 package com.android.server.display.plugin;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.text.TextUtils;
22 import android.util.Slog;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 import com.android.internal.os.SystemServerClassLoaderFactory;
26 import com.android.server.display.feature.DisplayManagerFlags;
27 
28 import dalvik.system.PathClassLoader;
29 
30 import java.io.PrintWriter;
31 import java.lang.reflect.InvocationTargetException;
32 import java.util.Collections;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Set;
36 
37 /**
38  * Responsible for loading Plugins. Plugins and PluginSupplier are loaded from
39  * standalone system jar.
40  * Plugin manager will look for PROVIDER_IMPL_CLASS in configured jar.
41  * After device booted, PluginManager will delegate this call to each Plugin
42  */
43 public class PluginManager {
44     private static final String PROVIDER_IMPL_CLASS =
45             "com.android.server.display.plugin.PluginsProviderImpl";
46     private static final String TAG = "PluginManager";
47 
48     private final PluginStorage mPluginStorage;
49     private final List<Plugin> mPlugins;
50 
PluginManager(Context context, DisplayManagerFlags flags)51     public PluginManager(Context context, DisplayManagerFlags flags) {
52         this(context, flags, new Injector());
53     }
54 
55     @VisibleForTesting
PluginManager(Context context, DisplayManagerFlags flags, Injector injector)56     PluginManager(Context context, DisplayManagerFlags flags, Injector injector) {
57         Set<PluginType<?>> enabledTypes = injector.getEnabledPluginTypes(flags);
58         mPluginStorage = injector.getPluginStorage(enabledTypes);
59         if (flags.isPluginManagerEnabled()) {
60             mPlugins = Collections.unmodifiableList(injector.loadPlugins(
61                     context, mPluginStorage, enabledTypes));
62             Slog.d(TAG, "loaded Plugins:" + mPlugins);
63         } else {
64             mPlugins = List.of();
65             Slog.d(TAG, "PluginManager disabled");
66         }
67     }
68 
69     /**
70      * Forwards boot completed event to Plugins
71      */
onBootCompleted()72     public void onBootCompleted() {
73         mPlugins.forEach(Plugin::onBootCompleted);
74     }
75 
76     /**
77      * Adds change listener for particular plugin type
78      */
subscribe(PluginType<T> type, String uniqueDisplayId, PluginChangeListener<T> listener)79     public <T> void subscribe(PluginType<T> type, String uniqueDisplayId,
80             PluginChangeListener<T> listener) {
81         mPluginStorage.addListener(type, uniqueDisplayId, listener);
82     }
83 
84     /**
85      * Removes change listener
86      */
unsubscribe(PluginType<T> type, String uniqueDisplayId, PluginChangeListener<T> listener)87     public <T> void unsubscribe(PluginType<T> type, String uniqueDisplayId,
88             PluginChangeListener<T> listener) {
89         mPluginStorage.removeListener(type, uniqueDisplayId, listener);
90     }
91 
92     /**
93      * Print the object's state and debug information into the given stream.
94      */
dump(PrintWriter pw)95     public void dump(PrintWriter pw) {
96         pw.println("PluginManager:");
97         mPluginStorage.dump(pw);
98         for (Plugin plugin : mPlugins) {
99             plugin.dump(pw);
100         }
101     }
102 
103     /**
104      * Listens for changes in PluginStorage for a particular type
105      * @param <T> plugin value type
106      */
107     public interface PluginChangeListener<T> {
108         /**
109          * Called when Plugin value changed
110          */
onChanged(@ullable T value)111         void onChanged(@Nullable T value);
112     }
113 
114     static class Injector {
115 
getEnabledPluginTypes(DisplayManagerFlags flags)116         Set<PluginType<?>> getEnabledPluginTypes(DisplayManagerFlags flags) {
117             Set<PluginType<?>> enabledTypes = new HashSet<>();
118             if (flags.isHdrOverrideEnabled()) {
119                 enabledTypes.add(PluginType.HDR_BOOST_OVERRIDE);
120             }
121             return enabledTypes;
122         }
123 
getPluginStorage(Set<PluginType<?>> enabledTypes)124         PluginStorage getPluginStorage(Set<PluginType<?>> enabledTypes) {
125             return new PluginStorage(enabledTypes);
126         }
127 
loadPlugins(Context context, PluginStorage storage, Set<PluginType<?>> enabledTypes)128         List<Plugin> loadPlugins(Context context, PluginStorage storage,
129                 Set<PluginType<?>> enabledTypes) {
130             String providerJarPath = context
131                     .getString(com.android.internal.R.string.config_pluginsProviderJarPath);
132             Slog.d(TAG, "loading plugins from:" + providerJarPath);
133             if (TextUtils.isEmpty(providerJarPath)) {
134                 return List.of();
135             }
136             try {
137                 PathClassLoader pathClassLoader =
138                         SystemServerClassLoaderFactory.getOrCreateClassLoader(
139                                 providerJarPath, getClass().getClassLoader(), false);
140                 @SuppressWarnings("PrivateApi")
141                 Class<? extends PluginsProvider> cp = pathClassLoader.loadClass(PROVIDER_IMPL_CLASS)
142                         .asSubclass(PluginsProvider.class);
143                 PluginsProvider provider = cp.getDeclaredConstructor().newInstance();
144                 return provider.getPlugins(context, storage, enabledTypes);
145             } catch (ClassNotFoundException e) {
146                 Slog.e(TAG, "loading failed: " + PROVIDER_IMPL_CLASS + " is not found in"
147                         + providerJarPath, e);
148             } catch (InvocationTargetException | InstantiationException | IllegalAccessException
149                      | NoSuchMethodException e) {
150                 Slog.e(TAG, "Class instantiation failed", e);
151             }
152             return List.of();
153         }
154     }
155 }
156