Merge "Daggerize Plugin code." into sc-v2-dev
This commit is contained in:
@@ -15,31 +15,20 @@
|
|||||||
package com.android.systemui.shared.plugins;
|
package com.android.systemui.shared.plugins;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Looper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides necessary components for initializing {@link PluginManagerImpl}.
|
* Provides necessary components for initializing {@link PluginManagerImpl}.
|
||||||
*/
|
*/
|
||||||
public interface PluginInitializer {
|
public interface PluginInitializer {
|
||||||
|
|
||||||
Looper getBgLooper();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from the bg looper during initialization of {@link PluginManagerImpl}.
|
* Return a list of plugins that don't get disabled when an exception occurs.
|
||||||
*/
|
*/
|
||||||
void onPluginManagerInit();
|
String[] getPrivilegedPlugins(Context context);
|
||||||
|
|
||||||
String[] getWhitelistedPlugins(Context context);
|
|
||||||
|
|
||||||
PluginEnabler getPluginEnabler(Context context);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from {@link PluginManagerImpl#handleWtfs()}.
|
* Called from {@link PluginInstanceManager}.
|
||||||
*/
|
*/
|
||||||
void handleWtfs();
|
void handleWtfs();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if pluging manager should run in debug mode.
|
|
||||||
*/
|
|
||||||
boolean isDebuggable();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,17 +67,13 @@ public class PluginInstanceManager<T extends Plugin> {
|
|||||||
private final PackageManager mPm;
|
private final PackageManager mPm;
|
||||||
private final PluginManagerImpl mManager;
|
private final PluginManagerImpl mManager;
|
||||||
private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
|
private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
|
||||||
|
private final PluginInitializer mInitializer;
|
||||||
|
|
||||||
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
|
|
||||||
boolean allowMultiple, Looper looper, VersionInfo version, PluginManagerImpl manager) {
|
|
||||||
this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
|
|
||||||
manager, manager.isDebuggable(), manager.getWhitelistedPlugins());
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
PluginInstanceManager(Context context, PackageManager pm, String action,
|
PluginInstanceManager(Context context, PackageManager pm, String action,
|
||||||
PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
|
PluginListener<T> listener, boolean allowMultiple, Looper looper, VersionInfo version,
|
||||||
PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
|
PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist,
|
||||||
|
PluginInitializer initializer) {
|
||||||
|
mInitializer = initializer;
|
||||||
mMainHandler = new MainHandler(Looper.getMainLooper());
|
mMainHandler = new MainHandler(Looper.getMainLooper());
|
||||||
mPluginHandler = new PluginHandler(looper);
|
mPluginHandler = new PluginHandler(looper);
|
||||||
mManager = manager;
|
mManager = manager;
|
||||||
@@ -214,7 +210,7 @@ public class PluginInstanceManager<T extends Plugin> {
|
|||||||
if (DEBUG) Log.d(TAG, "onPluginConnected");
|
if (DEBUG) Log.d(TAG, "onPluginConnected");
|
||||||
PluginPrefs.setHasPlugins(mContext);
|
PluginPrefs.setHasPlugins(mContext);
|
||||||
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
|
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
|
||||||
mManager.handleWtfs();
|
mInitializer.handleWtfs();
|
||||||
if (!(msg.obj instanceof PluginFragment)) {
|
if (!(msg.obj instanceof PluginFragment)) {
|
||||||
// Only call onDestroy for plugins that aren't fragments, as fragments
|
// Only call onDestroy for plugins that aren't fragments, as fragments
|
||||||
// will get the onCreate as part of the fragment lifecycle.
|
// will get the onCreate as part of the fragment lifecycle.
|
||||||
@@ -417,6 +413,33 @@ public class PluginInstanceManager<T extends Plugin> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a {@link PluginInstanceManager}
|
||||||
|
*/
|
||||||
|
public static class Factory {
|
||||||
|
private final Context mContext;
|
||||||
|
private final PackageManager mPackageManager;
|
||||||
|
private final Looper mLooper;
|
||||||
|
private final PluginInitializer mInitializer;
|
||||||
|
|
||||||
|
public Factory(Context context, PackageManager packageManager, Looper looper,
|
||||||
|
PluginInitializer initializer) {
|
||||||
|
mContext = context;
|
||||||
|
mPackageManager = packageManager;
|
||||||
|
mLooper = looper;
|
||||||
|
mInitializer = initializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
<T extends Plugin> PluginInstanceManager<T> create(
|
||||||
|
String action,
|
||||||
|
PluginListener<T> listener, boolean allowMultiple, VersionInfo version,
|
||||||
|
PluginManagerImpl manager, boolean debuggable, String[] pluginWhitelist) {
|
||||||
|
return new PluginInstanceManager<>(mContext, mPackageManager, action, listener,
|
||||||
|
allowMultiple, mLooper, version, manager, debuggable, pluginWhitelist,
|
||||||
|
mInitializer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class PluginContextWrapper extends ContextWrapper {
|
public static class PluginContextWrapper extends ContextWrapper {
|
||||||
private final ClassLoader mClassLoader;
|
private final ClassLoader mClassLoader;
|
||||||
private LayoutInflater mInflater;
|
private LayoutInflater mInflater;
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ public interface PluginManager {
|
|||||||
// must be one of the channels created in NotificationChannels.java
|
// must be one of the channels created in NotificationChannels.java
|
||||||
String NOTIFICATION_CHANNEL_ID = "ALR";
|
String NOTIFICATION_CHANNEL_ID = "ALR";
|
||||||
|
|
||||||
String[] getWhitelistedPlugins();
|
/** Returns plugins that don't get disabled when an exceptoin occurs. */
|
||||||
|
String[] getPrivilegedPlugins();
|
||||||
|
|
||||||
<T extends Plugin> T getOneShotPlugin(Class<T> cls);
|
<T extends Plugin> T getOneShotPlugin(Class<T> cls);
|
||||||
<T extends Plugin> T getOneShotPlugin(String action, Class<?> cls);
|
<T extends Plugin> T getOneShotPlugin(String action, Class<?> cls);
|
||||||
@@ -38,7 +39,7 @@ public interface PluginManager {
|
|||||||
<T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
<T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
||||||
Class<?> cls);
|
Class<?> cls);
|
||||||
<T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
<T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
||||||
Class cls, boolean allowMultiple);
|
Class<?> cls, boolean allowMultiple);
|
||||||
|
|
||||||
void removePluginListener(PluginListener<?> listener);
|
void removePluginListener(PluginListener<?> listener);
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -39,7 +38,6 @@ import android.util.ArraySet;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
|
||||||
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
||||||
import com.android.systemui.plugins.Plugin;
|
import com.android.systemui.plugins.Plugin;
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.systemui.plugins.PluginListener;
|
||||||
@@ -56,6 +54,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see Plugin
|
* @see Plugin
|
||||||
*/
|
*/
|
||||||
@@ -64,57 +64,45 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
private static final String TAG = PluginManagerImpl.class.getSimpleName();
|
private static final String TAG = PluginManagerImpl.class.getSimpleName();
|
||||||
static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
|
static final String DISABLE_PLUGIN = "com.android.systemui.action.DISABLE_PLUGIN";
|
||||||
|
|
||||||
private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
|
private final ArrayMap<PluginListener<?>, PluginInstanceManager<?>> mPluginMap
|
||||||
= new ArrayMap<>();
|
= new ArrayMap<>();
|
||||||
private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
|
private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
|
||||||
private final ArraySet<String> mOneShotPackages = new ArraySet<>();
|
private final ArraySet<String> mOneShotPackages = new ArraySet<>();
|
||||||
private final ArraySet<String> mWhitelistedPlugins = new ArraySet<>();
|
private final ArraySet<String> mPrivilegedPlugins = new ArraySet<>();
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final PluginInstanceManagerFactory mFactory;
|
private final PluginInstanceManager.Factory mInstanceManagerFactory;
|
||||||
private final boolean mIsDebuggable;
|
private final boolean mIsDebuggable;
|
||||||
private final PluginPrefs mPluginPrefs;
|
private final PluginPrefs mPluginPrefs;
|
||||||
private final PluginEnabler mPluginEnabler;
|
private final PluginEnabler mPluginEnabler;
|
||||||
private final PluginInitializer mPluginInitializer;
|
|
||||||
private ClassLoaderFilter mParentClassLoader;
|
private ClassLoaderFilter mParentClassLoader;
|
||||||
private boolean mListening;
|
private boolean mListening;
|
||||||
private boolean mHasOneShot;
|
private boolean mHasOneShot;
|
||||||
private Looper mLooper;
|
|
||||||
|
|
||||||
public PluginManagerImpl(Context context, PluginInitializer initializer) {
|
public PluginManagerImpl(Context context,
|
||||||
this(context, new PluginInstanceManagerFactory(), initializer.isDebuggable(),
|
PluginInstanceManager.Factory instanceManagerFactory,
|
||||||
Thread.getUncaughtExceptionPreHandler(), initializer);
|
boolean debuggable,
|
||||||
}
|
Optional<UncaughtExceptionHandler> defaultHandlerOptional,
|
||||||
|
PluginEnabler pluginEnabler,
|
||||||
@VisibleForTesting
|
PluginPrefs pluginPrefs,
|
||||||
PluginManagerImpl(Context context, PluginInstanceManagerFactory factory, boolean debuggable,
|
String[] privilegedPlugins) {
|
||||||
UncaughtExceptionHandler defaultHandler, final PluginInitializer initializer) {
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mFactory = factory;
|
mInstanceManagerFactory = instanceManagerFactory;
|
||||||
mLooper = initializer.getBgLooper();
|
|
||||||
mIsDebuggable = debuggable;
|
mIsDebuggable = debuggable;
|
||||||
mWhitelistedPlugins.addAll(Arrays.asList(initializer.getWhitelistedPlugins(mContext)));
|
mPrivilegedPlugins.addAll(Arrays.asList(privilegedPlugins));
|
||||||
mPluginPrefs = new PluginPrefs(mContext);
|
mPluginPrefs = pluginPrefs;
|
||||||
mPluginEnabler = initializer.getPluginEnabler(mContext);
|
mPluginEnabler = pluginEnabler;
|
||||||
mPluginInitializer = initializer;
|
|
||||||
|
|
||||||
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
|
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
|
||||||
defaultHandler);
|
defaultHandlerOptional);
|
||||||
Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
|
Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
|
||||||
|
|
||||||
new Handler(mLooper).post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
initializer.onPluginManagerInit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDebuggable() {
|
public boolean isDebuggable() {
|
||||||
return mIsDebuggable;
|
return mIsDebuggable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getWhitelistedPlugins() {
|
public String[] getPrivilegedPlugins() {
|
||||||
return mWhitelistedPlugins.toArray(new String[0]);
|
return mPrivilegedPlugins.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginEnabler getPluginEnabler() {
|
public PluginEnabler getPluginEnabler() {
|
||||||
@@ -138,9 +126,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
throw new RuntimeException("Must be called from UI thread");
|
throw new RuntimeException("Must be called from UI thread");
|
||||||
}
|
}
|
||||||
// Passing null causes compiler to complain about incompatible (generic) types.
|
// Passing null causes compiler to complain about incompatible (generic) types.
|
||||||
PluginListener<Plugin> dummy = null;
|
PluginListener<T> dummy = null;
|
||||||
PluginInstanceManager<T> p = mFactory.createPluginInstanceManager(mContext, action, dummy,
|
PluginInstanceManager<T> p = mInstanceManagerFactory.create(
|
||||||
false, mLooper, cls, this);
|
action, dummy, false, new VersionInfo().addClass(cls), this,
|
||||||
|
isDebuggable(), getPrivilegedPlugins());
|
||||||
mPluginPrefs.addAction(action);
|
mPluginPrefs.addAction(action);
|
||||||
PluginInfo<T> info = p.getPlugin();
|
PluginInfo<T> info = p.getPlugin();
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
@@ -167,10 +156,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
||||||
Class cls, boolean allowMultiple) {
|
Class<?> cls, boolean allowMultiple) {
|
||||||
mPluginPrefs.addAction(action);
|
mPluginPrefs.addAction(action);
|
||||||
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
|
PluginInstanceManager<T> p = mInstanceManagerFactory.create(action, listener, allowMultiple,
|
||||||
allowMultiple, mLooper, cls, this);
|
new VersionInfo().addClass(cls), this, isDebuggable(),
|
||||||
|
getPrivilegedPlugins());
|
||||||
p.loadAll();
|
p.loadAll();
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
mPluginMap.put(listener, p);
|
mPluginMap.put(listener, p);
|
||||||
@@ -218,7 +208,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
|
if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (PluginInstanceManager manager : mPluginMap.values()) {
|
for (PluginInstanceManager<?> manager : mPluginMap.values()) {
|
||||||
manager.loadAll();
|
manager.loadAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,8 +216,8 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
ComponentName component = ComponentName.unflattenFromString(
|
ComponentName component = ComponentName.unflattenFromString(
|
||||||
uri.toString().substring(10));
|
uri.toString().substring(10));
|
||||||
if (isPluginWhitelisted(component)) {
|
if (isPluginPrivileged(component)) {
|
||||||
// Don't disable whitelisted plugins as they are a part of the OS.
|
// Don't disable privileged plugins as they are a part of the OS.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getPluginEnabler().setDisabled(component, PluginEnabler.DISABLED_INVALID_VERSION);
|
getPluginEnabler().setDisabled(component, PluginEnabler.DISABLED_INVALID_VERSION);
|
||||||
@@ -287,11 +277,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
}
|
}
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
|
if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
|
||||||
for (PluginInstanceManager manager : mPluginMap.values()) {
|
for (PluginInstanceManager<?> manager : mPluginMap.values()) {
|
||||||
manager.onPackageChange(pkg);
|
manager.onPackageChange(pkg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (PluginInstanceManager manager : mPluginMap.values()) {
|
for (PluginInstanceManager<?> manager : mPluginMap.values()) {
|
||||||
manager.onPackageRemoved(pkg);
|
manager.onPackageRemoved(pkg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,8 +291,8 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
|
|
||||||
/** Returns class loader specific for the given plugin. */
|
/** Returns class loader specific for the given plugin. */
|
||||||
public ClassLoader getClassLoader(ApplicationInfo appInfo) {
|
public ClassLoader getClassLoader(ApplicationInfo appInfo) {
|
||||||
if (!mIsDebuggable && !isPluginPackageWhitelisted(appInfo.packageName)) {
|
if (!mIsDebuggable && !isPluginPackagePrivileged(appInfo.packageName)) {
|
||||||
Log.w(TAG, "Cannot get class loader for non-whitelisted plugin. Src:"
|
Log.w(TAG, "Cannot get class loader for non-privileged plugin. Src:"
|
||||||
+ appInfo.sourceDir + ", pkg: " + appInfo.packageName);
|
+ appInfo.sourceDir + ", pkg: " + appInfo.packageName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -345,32 +335,18 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleWtfs() {
|
|
||||||
mPluginInitializer.handleWtfs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
pw.println(String.format(" plugin map (%d):", mPluginMap.size()));
|
pw.println(String.format(" plugin map (%d):", mPluginMap.size()));
|
||||||
for (PluginListener listener : mPluginMap.keySet()) {
|
for (PluginListener<?> listener : mPluginMap.keySet()) {
|
||||||
pw.println(String.format(" %s -> %s",
|
pw.println(String.format(" %s -> %s",
|
||||||
listener, mPluginMap.get(listener)));
|
listener, mPluginMap.get(listener)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
private boolean isPluginPackagePrivileged(String packageName) {
|
||||||
public static class PluginInstanceManagerFactory {
|
for (String componentNameOrPackage : mPrivilegedPlugins) {
|
||||||
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
|
|
||||||
String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,
|
|
||||||
Class<?> cls, PluginManagerImpl manager) {
|
|
||||||
return new PluginInstanceManager(context, action, listener, allowMultiple, looper,
|
|
||||||
new VersionInfo().addClass(cls), manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPluginPackageWhitelisted(String packageName) {
|
|
||||||
for (String componentNameOrPackage : mWhitelistedPlugins) {
|
|
||||||
ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
|
ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
|
||||||
if (componentName != null) {
|
if (componentName != null) {
|
||||||
if (componentName.getPackageName().equals(packageName)) {
|
if (componentName.getPackageName().equals(packageName)) {
|
||||||
@@ -383,8 +359,8 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPluginWhitelisted(ComponentName pluginName) {
|
private boolean isPluginPrivileged(ComponentName pluginName) {
|
||||||
for (String componentNameOrPackage : mWhitelistedPlugins) {
|
for (String componentNameOrPackage : mPrivilegedPlugins) {
|
||||||
ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
|
ComponentName componentName = ComponentName.unflattenFromString(componentNameOrPackage);
|
||||||
if (componentName != null) {
|
if (componentName != null) {
|
||||||
if (componentName.equals(pluginName)) {
|
if (componentName.equals(pluginName)) {
|
||||||
@@ -417,16 +393,20 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class PluginExceptionHandler implements UncaughtExceptionHandler {
|
private class PluginExceptionHandler implements UncaughtExceptionHandler {
|
||||||
private final UncaughtExceptionHandler mHandler;
|
private final Optional<UncaughtExceptionHandler> mExceptionHandlerOptional;
|
||||||
|
|
||||||
private PluginExceptionHandler(UncaughtExceptionHandler handler) {
|
private PluginExceptionHandler(
|
||||||
mHandler = handler;
|
Optional<UncaughtExceptionHandler> exceptionHandlerOptional) {
|
||||||
|
mExceptionHandlerOptional = exceptionHandlerOptional;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uncaughtException(Thread thread, Throwable throwable) {
|
public void uncaughtException(Thread thread, Throwable throwable) {
|
||||||
if (SystemProperties.getBoolean("plugin.debugging", false)) {
|
if (SystemProperties.getBoolean("plugin.debugging", false)) {
|
||||||
mHandler.uncaughtException(thread, throwable);
|
Throwable finalThrowable = throwable;
|
||||||
|
mExceptionHandlerOptional.ifPresent(
|
||||||
|
handler -> handler.uncaughtException(thread, finalThrowable));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Search for and disable plugins that may have been involved in this crash.
|
// Search for and disable plugins that may have been involved in this crash.
|
||||||
@@ -436,7 +416,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
// disable all the plugins, so we can be sure that SysUI is running as
|
// disable all the plugins, so we can be sure that SysUI is running as
|
||||||
// best as possible.
|
// best as possible.
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (PluginInstanceManager manager : mPluginMap.values()) {
|
for (PluginInstanceManager<?> manager : mPluginMap.values()) {
|
||||||
disabledAny |= manager.disableAll();
|
disabledAny |= manager.disableAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,7 +426,9 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run the normal exception handler so we can crash and cleanup our state.
|
// Run the normal exception handler so we can crash and cleanup our state.
|
||||||
mHandler.uncaughtException(thread, throwable);
|
Throwable finalThrowable = throwable;
|
||||||
|
mExceptionHandlerOptional.ifPresent(
|
||||||
|
handler -> handler.uncaughtException(thread, finalThrowable));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkStack(Throwable throwable) {
|
private boolean checkStack(Throwable throwable) {
|
||||||
@@ -454,7 +436,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
|||||||
boolean disabledAny = false;
|
boolean disabledAny = false;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (StackTraceElement element : throwable.getStackTrace()) {
|
for (StackTraceElement element : throwable.getStackTrace()) {
|
||||||
for (PluginInstanceManager manager : mPluginMap.values()) {
|
for (PluginInstanceManager<?> manager : mPluginMap.values()) {
|
||||||
disabledAny |= manager.checkAndDisable(element.getClassName());
|
disabledAny |= manager.checkAndDisable(element.getClassName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,21 +68,15 @@ import com.android.systemui.navigationbar.NavigationBarController;
|
|||||||
import com.android.systemui.navigationbar.NavigationBarOverlayController;
|
import com.android.systemui.navigationbar.NavigationBarOverlayController;
|
||||||
import com.android.systemui.navigationbar.NavigationModeController;
|
import com.android.systemui.navigationbar.NavigationModeController;
|
||||||
import com.android.systemui.navigationbar.TaskbarDelegate;
|
import com.android.systemui.navigationbar.TaskbarDelegate;
|
||||||
import com.android.systemui.plugins.PluginInitializerImpl;
|
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.qs.ReduceBrightColorsController;
|
import com.android.systemui.qs.ReduceBrightColorsController;
|
||||||
import com.android.systemui.recents.OverviewProxyService;
|
import com.android.systemui.recents.OverviewProxyService;
|
||||||
import com.android.systemui.recents.Recents;
|
import com.android.systemui.recents.Recents;
|
||||||
import com.android.systemui.settings.UserTracker;
|
import com.android.systemui.settings.UserTracker;
|
||||||
import com.android.systemui.shared.plugins.PluginManager;
|
|
||||||
import com.android.systemui.shared.plugins.PluginManagerImpl;
|
|
||||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||||
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
|
import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
|
||||||
import com.android.systemui.shared.system.TaskStackChangeListeners;
|
import com.android.systemui.shared.system.TaskStackChangeListeners;
|
||||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||||
import com.android.unfold.UnfoldTransitionFactory;
|
|
||||||
import com.android.unfold.UnfoldTransitionProgressProvider;
|
|
||||||
import com.android.unfold.config.UnfoldTransitionConfig;
|
|
||||||
import com.android.systemui.statusbar.CommandQueue;
|
import com.android.systemui.statusbar.CommandQueue;
|
||||||
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
import com.android.systemui.statusbar.NotificationRemoteInputManager;
|
||||||
import com.android.systemui.statusbar.NotificationShadeDepthController;
|
import com.android.systemui.statusbar.NotificationShadeDepthController;
|
||||||
@@ -98,6 +92,9 @@ import com.android.systemui.statusbar.policy.NetworkController;
|
|||||||
import com.android.systemui.theme.ThemeOverlayApplier;
|
import com.android.systemui.theme.ThemeOverlayApplier;
|
||||||
import com.android.systemui.util.leak.LeakDetector;
|
import com.android.systemui.util.leak.LeakDetector;
|
||||||
import com.android.systemui.util.settings.SecureSettings;
|
import com.android.systemui.util.settings.SecureSettings;
|
||||||
|
import com.android.unfold.UnfoldTransitionFactory;
|
||||||
|
import com.android.unfold.UnfoldTransitionProgressProvider;
|
||||||
|
import com.android.unfold.config.UnfoldTransitionConfig;
|
||||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||||
import com.android.wm.shell.pip.Pip;
|
import com.android.wm.shell.pip.Pip;
|
||||||
|
|
||||||
@@ -195,13 +192,6 @@ public class DependencyProvider {
|
|||||||
return new MetricsLogger();
|
return new MetricsLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
|
||||||
@Provides
|
|
||||||
@SysUISingleton
|
|
||||||
public PluginManager providePluginManager(Context context) {
|
|
||||||
return new PluginManagerImpl(context, new PluginInitializerImpl());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import android.util.DisplayMetrics;
|
|||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.internal.logging.UiEventLoggerImpl;
|
import com.android.internal.logging.UiEventLoggerImpl;
|
||||||
import com.android.systemui.dagger.qualifiers.TestHarness;
|
import com.android.systemui.dagger.qualifiers.TestHarness;
|
||||||
|
import com.android.systemui.plugins.PluginsModule;
|
||||||
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
|
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -47,7 +48,9 @@ import dagger.Provides;
|
|||||||
*/
|
*/
|
||||||
@Module(includes = {
|
@Module(includes = {
|
||||||
FrameworkServicesModule.class,
|
FrameworkServicesModule.class,
|
||||||
GlobalConcurrencyModule.class})
|
GlobalConcurrencyModule.class,
|
||||||
|
PluginsModule.class,
|
||||||
|
})
|
||||||
public class GlobalModule {
|
public class GlobalModule {
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ package com.android.systemui.dagger;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.android.systemui.util.concurrency.ThreadFactory;
|
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.BindsInstance;
|
import dagger.BindsInstance;
|
||||||
@@ -55,9 +53,4 @@ public interface GlobalRootComponent {
|
|||||||
* Builder for a SysUIComponent.
|
* Builder for a SysUIComponent.
|
||||||
*/
|
*/
|
||||||
SysUIComponent.Builder getSysUIComponent();
|
SysUIComponent.Builder getSysUIComponent();
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a {@link ThreadFactory}.
|
|
||||||
*/
|
|
||||||
ThreadFactory createThreadFactory();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,25 +17,27 @@ package com.android.systemui.plugins;
|
|||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
|
|
||||||
import com.android.systemui.Dependency;
|
import com.android.systemui.Dependency;
|
||||||
import com.android.systemui.dagger.SysUISingleton;
|
|
||||||
import com.android.systemui.plugins.PluginDependency.DependencyProvider;
|
import com.android.systemui.plugins.PluginDependency.DependencyProvider;
|
||||||
import com.android.systemui.shared.plugins.PluginManager;
|
import com.android.systemui.shared.plugins.PluginManager;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Lazy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@Singleton
|
||||||
public class PluginDependencyProvider extends DependencyProvider {
|
public class PluginDependencyProvider extends DependencyProvider {
|
||||||
|
|
||||||
private final ArrayMap<Class<?>, Object> mDependencies = new ArrayMap<>();
|
private final ArrayMap<Class<?>, Object> mDependencies = new ArrayMap<>();
|
||||||
private final PluginManager mManager;
|
private final Lazy<PluginManager> mManagerLazy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public PluginDependencyProvider(PluginManager manager) {
|
public PluginDependencyProvider(Lazy<PluginManager> managerLazy) {
|
||||||
mManager = manager;
|
mManagerLazy = managerLazy;
|
||||||
PluginDependency.sProvider = this;
|
PluginDependency.sProvider = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +53,7 @@ public class PluginDependencyProvider extends DependencyProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
<T> T get(Plugin p, Class<T> cls) {
|
<T> T get(Plugin p, Class<T> cls) {
|
||||||
if (!mManager.dependsOn(p, cls)) {
|
if (!mManagerLazy.get().dependsOn(p, cls)) {
|
||||||
throw new IllegalArgumentException(p.getClass() + " does not depend on " + cls);
|
throw new IllegalArgumentException(p.getClass() + " does not depend on " + cls);
|
||||||
}
|
}
|
||||||
synchronized (mDependencies) {
|
synchronized (mDependencies) {
|
||||||
|
|||||||
@@ -22,16 +22,22 @@ import android.content.pm.PackageManager;
|
|||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.systemui.shared.plugins.PluginEnabler;
|
import com.android.systemui.shared.plugins.PluginEnabler;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Singleton
|
||||||
public class PluginEnablerImpl implements PluginEnabler {
|
public class PluginEnablerImpl implements PluginEnabler {
|
||||||
private static final String CRASH_DISABLED_PLUGINS_PREF_FILE = "auto_disabled_plugins_prefs";
|
private static final String CRASH_DISABLED_PLUGINS_PREF_FILE = "auto_disabled_plugins_prefs";
|
||||||
|
|
||||||
private PackageManager mPm;
|
private final PackageManager mPm;
|
||||||
private final SharedPreferences mAutoDisabledPrefs;
|
private final SharedPreferences mAutoDisabledPrefs;
|
||||||
|
|
||||||
public PluginEnablerImpl(Context context) {
|
public PluginEnablerImpl(Context context) {
|
||||||
this(context, context.getPackageManager());
|
this(context, context.getPackageManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
@VisibleForTesting public PluginEnablerImpl(Context context, PackageManager pm) {
|
@VisibleForTesting public PluginEnablerImpl(Context context, PackageManager pm) {
|
||||||
mAutoDisabledPrefs = context.getSharedPreferences(
|
mAutoDisabledPrefs = context.getSharedPreferences(
|
||||||
CRASH_DISABLED_PLUGINS_PREF_FILE, Context.MODE_PRIVATE);
|
CRASH_DISABLED_PLUGINS_PREF_FILE, Context.MODE_PRIVATE);
|
||||||
|
|||||||
@@ -15,16 +15,17 @@
|
|||||||
package com.android.systemui.plugins;
|
package com.android.systemui.plugins;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.systemui.Dependency;
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.shared.plugins.PluginEnabler;
|
|
||||||
import com.android.systemui.shared.plugins.PluginInitializer;
|
import com.android.systemui.shared.plugins.PluginInitializer;
|
||||||
import com.android.systemui.shared.plugins.PluginManagerImpl;
|
import com.android.systemui.shared.plugins.PluginManagerImpl;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Singleton
|
||||||
public class PluginInitializerImpl implements PluginInitializer {
|
public class PluginInitializerImpl implements PluginInitializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,44 +34,24 @@ public class PluginInitializerImpl implements PluginInitializer {
|
|||||||
private static final boolean WTFS_SHOULD_CRASH = false;
|
private static final boolean WTFS_SHOULD_CRASH = false;
|
||||||
private boolean mWtfsSet;
|
private boolean mWtfsSet;
|
||||||
|
|
||||||
@Override
|
@Inject
|
||||||
public Looper getBgLooper() {
|
public PluginInitializerImpl(PluginDependencyProvider dependencyProvider) {
|
||||||
return Dependency.get(Dependency.BG_LOOPER);
|
dependencyProvider.allowPluginDependency(ActivityStarter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginManagerInit() {
|
public String[] getPrivilegedPlugins(Context context) {
|
||||||
// Plugin dependencies that don't have another good home can go here, but
|
|
||||||
// dependencies that have better places to init can happen elsewhere.
|
|
||||||
Dependency.get(PluginDependencyProvider.class)
|
|
||||||
.allowPluginDependency(ActivityStarter.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getWhitelistedPlugins(Context context) {
|
|
||||||
return context.getResources().getStringArray(R.array.config_pluginWhitelist);
|
return context.getResources().getStringArray(R.array.config_pluginWhitelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginEnabler getPluginEnabler(Context context) {
|
|
||||||
return new PluginEnablerImpl(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleWtfs() {
|
public void handleWtfs() {
|
||||||
if (WTFS_SHOULD_CRASH && !mWtfsSet) {
|
if (WTFS_SHOULD_CRASH && !mWtfsSet) {
|
||||||
mWtfsSet = true;
|
mWtfsSet = true;
|
||||||
Log.setWtfHandler(new Log.TerribleFailureHandler() {
|
Log.setWtfHandler((tag, what, system) -> {
|
||||||
@Override
|
throw new PluginManagerImpl.CrashWhilePluginActiveException(what);
|
||||||
public void onTerribleFailure(String tag, Log.TerribleFailure what,
|
|
||||||
boolean system) {
|
|
||||||
throw new PluginManagerImpl.CrashWhilePluginActiveException(what);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDebuggable() {
|
|
||||||
return Build.IS_DEBUGGABLE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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;
|
||||||
|
|
||||||
|
import static com.android.systemui.util.concurrency.GlobalConcurrencyModule.PRE_HANDLER;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import com.android.systemui.shared.plugins.PluginEnabler;
|
||||||
|
import com.android.systemui.shared.plugins.PluginInitializer;
|
||||||
|
import com.android.systemui.shared.plugins.PluginInstanceManager;
|
||||||
|
import com.android.systemui.shared.plugins.PluginManager;
|
||||||
|
import com.android.systemui.shared.plugins.PluginManagerImpl;
|
||||||
|
import com.android.systemui.shared.plugins.PluginPrefs;
|
||||||
|
import com.android.systemui.util.concurrency.ThreadFactory;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Binds;
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dagger Module for code related to plugins.
|
||||||
|
*
|
||||||
|
* Covers code both in com.android.systemui.plugins and code in
|
||||||
|
* com.android.systemui.shared.plugins.
|
||||||
|
*/
|
||||||
|
@Module
|
||||||
|
public abstract class PluginsModule {
|
||||||
|
public static final String PLUGIN_THREAD = "plugin_thread";
|
||||||
|
public static final String PLUGIN_DEBUG = "plugin_debug";
|
||||||
|
public static final String PLUGIN_PRIVILEGED = "plugin_privileged";
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Named(PLUGIN_DEBUG)
|
||||||
|
static boolean providesPluginDebug() {
|
||||||
|
return Build.IS_DEBUGGABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract PluginEnabler bindsPluginEnablerImpl(PluginEnablerImpl impl);
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract PluginInitializer bindsPluginInitializerImpl(PluginInitializerImpl impl);
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static PluginInstanceManager.Factory providePluginInstanceManagerFactory(Context context,
|
||||||
|
PackageManager packageManager, @Named(PLUGIN_THREAD) Looper pluginLooper,
|
||||||
|
PluginInitializer initializer) {
|
||||||
|
return new PluginInstanceManager.Factory(
|
||||||
|
context, packageManager, pluginLooper, initializer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
@Named(PLUGIN_THREAD)
|
||||||
|
static Looper providesPluginLooper(ThreadFactory threadFactory) {
|
||||||
|
return threadFactory.buildLooperOnNewThread("plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
static PluginManager providesPluginManager(
|
||||||
|
Context context,
|
||||||
|
PluginInstanceManager.Factory instanceManagerFactory,
|
||||||
|
@Named(PLUGIN_DEBUG) boolean debug,
|
||||||
|
@Named(PRE_HANDLER)
|
||||||
|
Optional<Thread.UncaughtExceptionHandler> uncaughtExceptionHandlerOptional,
|
||||||
|
PluginEnabler pluginEnabler,
|
||||||
|
PluginPrefs pluginPrefs,
|
||||||
|
@Named(PLUGIN_PRIVILEGED) String[] privilegedPlugins) {
|
||||||
|
return new PluginManagerImpl(context, instanceManagerFactory, debug,
|
||||||
|
uncaughtExceptionHandlerOptional, pluginEnabler, pluginPrefs,
|
||||||
|
privilegedPlugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
static PluginPrefs providesPluginPrefs(Context context) {
|
||||||
|
return new PluginPrefs(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Named(PLUGIN_PRIVILEGED)
|
||||||
|
static String[] providesPrivilegedPlugins(PluginInitializer initializer, Context context) {
|
||||||
|
return initializer.getPrivilegedPlugins(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -106,8 +106,8 @@ public class PluginFragment extends PreferenceFragment {
|
|||||||
PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
|
PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
|
||||||
apps.forEach(app -> {
|
apps.forEach(app -> {
|
||||||
if (!plugins.containsKey(app.packageName)) return;
|
if (!plugins.containsKey(app.packageName)) return;
|
||||||
if (ArrayUtils.contains(manager.getWhitelistedPlugins(), app.packageName)) {
|
if (ArrayUtils.contains(manager.getPrivilegedPlugins(), app.packageName)) {
|
||||||
// Don't manage whitelisted plugins, they are part of the OS.
|
// Don't manage privileged plugins, they are part of the OS.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SwitchPreference pref = new PluginPreference(prefContext, app, mPluginEnabler);
|
SwitchPreference pref = new PluginPreference(prefContext, app, mPluginEnabler);
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ import android.os.Looper;
|
|||||||
|
|
||||||
import com.android.systemui.dagger.qualifiers.Main;
|
import com.android.systemui.dagger.qualifiers.Main;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Binds;
|
import dagger.Binds;
|
||||||
@@ -35,6 +37,7 @@ import dagger.Provides;
|
|||||||
*/
|
*/
|
||||||
@Module
|
@Module
|
||||||
public abstract class GlobalConcurrencyModule {
|
public abstract class GlobalConcurrencyModule {
|
||||||
|
public static final String PRE_HANDLER = "pre_handler";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
|
* Binds {@link ThreadFactoryImpl} to {@link ThreadFactory}.
|
||||||
@@ -73,4 +76,11 @@ public abstract class GlobalConcurrencyModule {
|
|||||||
@Binds
|
@Binds
|
||||||
@Singleton
|
@Singleton
|
||||||
public abstract Execution provideExecution(ExecutionImpl execution);
|
public abstract Execution provideExecution(ExecutionImpl execution);
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Provides
|
||||||
|
@Named(PRE_HANDLER)
|
||||||
|
public static Optional<Thread.UncaughtExceptionHandler> providesUncaughtExceptionHandler() {
|
||||||
|
return Optional.ofNullable(Thread.getUncaughtExceptionPreHandler());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
|
|||||||
private PluginEnabler mMockEnabler;
|
private PluginEnabler mMockEnabler;
|
||||||
ComponentName mTestPluginComponentName =
|
ComponentName mTestPluginComponentName =
|
||||||
new ComponentName(WHITELISTED_PACKAGE, TestPlugin.class.getName());
|
new ComponentName(WHITELISTED_PACKAGE, TestPlugin.class.getName());
|
||||||
|
private PluginInitializer mInitializer;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
@@ -95,9 +96,10 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
|
|||||||
mMockEnabler = mock(PluginEnabler.class);
|
mMockEnabler = mock(PluginEnabler.class);
|
||||||
when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
|
when(mMockManager.getPluginEnabler()).thenReturn(mMockEnabler);
|
||||||
mMockVersionInfo = mock(VersionInfo.class);
|
mMockVersionInfo = mock(VersionInfo.class);
|
||||||
|
mInitializer = mock(PluginInitializer.class);
|
||||||
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
||||||
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
||||||
mMockManager, true, new String[0]);
|
mMockManager, true, new String[0], mInitializer);
|
||||||
sMockPlugin = mock(Plugin.class);
|
sMockPlugin = mock(Plugin.class);
|
||||||
when(sMockPlugin.getVersion()).thenReturn(1);
|
when(sMockPlugin.getVersion()).thenReturn(1);
|
||||||
}
|
}
|
||||||
@@ -194,7 +196,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
|
|||||||
// Create a version that thinks the build is not debuggable.
|
// Create a version that thinks the build is not debuggable.
|
||||||
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
||||||
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
||||||
mMockManager, false, new String[0]);
|
mMockManager, false, new String[0], mInitializer);
|
||||||
setupFakePmQuery();
|
setupFakePmQuery();
|
||||||
|
|
||||||
mPluginInstanceManager.loadAll();
|
mPluginInstanceManager.loadAll();
|
||||||
@@ -211,7 +213,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
|
|||||||
// Create a version that thinks the build is not debuggable.
|
// Create a version that thinks the build is not debuggable.
|
||||||
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
||||||
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
||||||
mMockManager, false, new String[] {WHITELISTED_PACKAGE});
|
mMockManager, false, new String[] {WHITELISTED_PACKAGE}, mInitializer);
|
||||||
setupFakePmQuery();
|
setupFakePmQuery();
|
||||||
|
|
||||||
mPluginInstanceManager.loadAll();
|
mPluginInstanceManager.loadAll();
|
||||||
@@ -255,7 +257,7 @@ public class PluginInstanceManagerTest extends SysuiTestCase {
|
|||||||
public void testDisableWhitelisted() throws Exception {
|
public void testDisableWhitelisted() throws Exception {
|
||||||
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
|
||||||
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
mMockListener, true, mHandlerThread.getLooper(), mMockVersionInfo,
|
||||||
mMockManager, false, new String[] {WHITELISTED_PACKAGE});
|
mMockManager, false, new String[] {WHITELISTED_PACKAGE}, mInitializer);
|
||||||
createPlugin(); // Get into valid created state.
|
createPlugin(); // Get into valid created state.
|
||||||
|
|
||||||
mPluginInstanceManager.disableAll();
|
mPluginInstanceManager.disableAll();
|
||||||
|
|||||||
@@ -30,19 +30,14 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.test.suitebuilder.annotation.SmallTest;
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.testing.TestableLooper;
|
|
||||||
import android.testing.TestableLooper.RunWithLooper;
|
import android.testing.TestableLooper.RunWithLooper;
|
||||||
|
|
||||||
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
||||||
import com.android.systemui.Dependency;
|
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.plugins.Plugin;
|
import com.android.systemui.plugins.Plugin;
|
||||||
import com.android.systemui.plugins.PluginEnablerImpl;
|
|
||||||
import com.android.systemui.plugins.PluginInitializerImpl;
|
|
||||||
import com.android.systemui.plugins.PluginListener;
|
import com.android.systemui.plugins.PluginListener;
|
||||||
import com.android.systemui.plugins.annotations.ProvidesInterface;
|
import com.android.systemui.plugins.annotations.ProvidesInterface;
|
||||||
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
|
import com.android.systemui.shared.plugins.PluginInstanceManager.PluginInfo;
|
||||||
import com.android.systemui.shared.plugins.PluginManagerImpl.PluginInstanceManagerFactory;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -51,6 +46,7 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
import java.lang.Thread.UncaughtExceptionHandler;
|
import java.lang.Thread.UncaughtExceptionHandler;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
@@ -59,11 +55,13 @@ public class PluginManagerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
private static final String WHITELISTED_PACKAGE = "com.android.systemui";
|
private static final String WHITELISTED_PACKAGE = "com.android.systemui";
|
||||||
|
|
||||||
private PluginInstanceManagerFactory mMockFactory;
|
private PluginInstanceManager.Factory mMockFactory;
|
||||||
private PluginInstanceManager mMockPluginInstance;
|
private PluginInstanceManager mMockPluginInstance;
|
||||||
private PluginManagerImpl mPluginManager;
|
private PluginManagerImpl mPluginManager;
|
||||||
private PluginListener mMockListener;
|
private PluginListener<?> mMockListener;
|
||||||
private PackageManager mMockPackageManager;
|
private PackageManager mMockPackageManager;
|
||||||
|
private PluginEnabler mPluginEnabler;
|
||||||
|
private PluginPrefs mPluginPrefs;
|
||||||
|
|
||||||
private UncaughtExceptionHandler mRealExceptionHandler;
|
private UncaughtExceptionHandler mRealExceptionHandler;
|
||||||
private UncaughtExceptionHandler mMockExceptionHandler;
|
private UncaughtExceptionHandler mMockExceptionHandler;
|
||||||
@@ -71,30 +69,23 @@ public class PluginManagerTest extends SysuiTestCase {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
mDependency.injectTestDependency(Dependency.BG_LOOPER,
|
|
||||||
TestableLooper.get(this).getLooper());
|
|
||||||
mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler();
|
mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler();
|
||||||
mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
|
mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
|
||||||
mMockFactory = mock(PluginInstanceManagerFactory.class);
|
mMockFactory = mock(PluginInstanceManager.Factory.class);
|
||||||
mMockPluginInstance = mock(PluginInstanceManager.class);
|
mMockPluginInstance = mock(PluginInstanceManager.class);
|
||||||
when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
|
mPluginEnabler = mock(PluginEnabler.class);
|
||||||
Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.any()))
|
mPluginPrefs = mock(PluginPrefs.class);
|
||||||
|
when(mMockFactory.create(Mockito.any(), Mockito.any(),
|
||||||
|
Mockito.anyBoolean(), Mockito.any(), Mockito.any(), Mockito.anyBoolean(),
|
||||||
|
Mockito.any()))
|
||||||
.thenReturn(mMockPluginInstance);
|
.thenReturn(mMockPluginInstance);
|
||||||
|
|
||||||
mMockPackageManager = mock(PackageManager.class);
|
mMockPackageManager = mock(PackageManager.class);
|
||||||
mPluginManager = new PluginManagerImpl(
|
mPluginManager = new PluginManagerImpl(
|
||||||
getContext(), mMockFactory, true,
|
getContext(), mMockFactory, true,
|
||||||
mMockExceptionHandler, new PluginInitializerImpl() {
|
Optional.of(mMockExceptionHandler), mPluginEnabler,
|
||||||
@Override
|
mPluginPrefs, new String[0]);
|
||||||
public String[] getWhitelistedPlugins(Context context) {
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PluginEnabler getPluginEnabler(Context context) {
|
|
||||||
return new PluginEnablerImpl(context, mMockPackageManager);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
resetExceptionHandler();
|
resetExceptionHandler();
|
||||||
mMockListener = mock(PluginListener.class);
|
mMockListener = mock(PluginListener.class);
|
||||||
}
|
}
|
||||||
@@ -127,13 +118,10 @@ public class PluginManagerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
@RunWithLooper(setAsMainLooper = true)
|
@RunWithLooper(setAsMainLooper = true)
|
||||||
public void testNonDebuggable_noWhitelist() {
|
public void testNonDebuggable_noWhitelist() {
|
||||||
mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
|
mPluginManager = new PluginManagerImpl(
|
||||||
mMockExceptionHandler, new PluginInitializerImpl() {
|
getContext(), mMockFactory, false,
|
||||||
@Override
|
Optional.of(mMockExceptionHandler), mPluginEnabler,
|
||||||
public String[] getWhitelistedPlugins(Context context) {
|
mPluginPrefs, new String[0]);
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
resetExceptionHandler();
|
resetExceptionHandler();
|
||||||
|
|
||||||
String sourceDir = "myPlugin";
|
String sourceDir = "myPlugin";
|
||||||
@@ -148,13 +136,10 @@ public class PluginManagerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
@RunWithLooper(setAsMainLooper = true)
|
@RunWithLooper(setAsMainLooper = true)
|
||||||
public void testNonDebuggable_whitelistedPkg() {
|
public void testNonDebuggable_whitelistedPkg() {
|
||||||
mPluginManager = new PluginManagerImpl(getContext(), mMockFactory, false,
|
mPluginManager = new PluginManagerImpl(
|
||||||
mMockExceptionHandler, new PluginInitializerImpl() {
|
getContext(), mMockFactory, false,
|
||||||
@Override
|
Optional.of(mMockExceptionHandler), mPluginEnabler,
|
||||||
public String[] getWhitelistedPlugins(Context context) {
|
mPluginPrefs, new String[] {WHITELISTED_PACKAGE});
|
||||||
return new String[] {WHITELISTED_PACKAGE};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
resetExceptionHandler();
|
resetExceptionHandler();
|
||||||
|
|
||||||
String sourceDir = "myPlugin";
|
String sourceDir = "myPlugin";
|
||||||
@@ -211,9 +196,7 @@ public class PluginManagerTest extends SysuiTestCase {
|
|||||||
intent.setData(Uri.parse("package://" + testComponent.flattenToString()));
|
intent.setData(Uri.parse("package://" + testComponent.flattenToString()));
|
||||||
mPluginManager.onReceive(mContext, intent);
|
mPluginManager.onReceive(mContext, intent);
|
||||||
verify(nm).cancel(eq(testComponent.getClassName()), eq(SystemMessage.NOTE_PLUGIN));
|
verify(nm).cancel(eq(testComponent.getClassName()), eq(SystemMessage.NOTE_PLUGIN));
|
||||||
verify(mMockPackageManager).setComponentEnabledSetting(eq(testComponent),
|
verify(mPluginEnabler).setDisabled(testComponent, PluginEnabler.DISABLED_INVALID_VERSION);
|
||||||
eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
|
|
||||||
eq(PackageManager.DONT_KILL_APP));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetExceptionHandler() {
|
private void resetExceptionHandler() {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import com.android.systemui.shared.plugins.PluginManager;
|
|||||||
|
|
||||||
public class FakePluginManager implements PluginManager {
|
public class FakePluginManager implements PluginManager {
|
||||||
|
|
||||||
private final BaseLeakChecker<PluginListener> mLeakChecker;
|
private final BaseLeakChecker<PluginListener<?>> mLeakChecker;
|
||||||
|
|
||||||
public FakePluginManager(LeakCheck test) {
|
public FakePluginManager(LeakCheck test) {
|
||||||
mLeakChecker = new BaseLeakChecker<>(test, "Plugin");
|
mLeakChecker = new BaseLeakChecker<>(test, "Plugin");
|
||||||
@@ -30,7 +30,7 @@ public class FakePluginManager implements PluginManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
public <T extends Plugin> void addPluginListener(String action, PluginListener<T> listener,
|
||||||
Class cls, boolean allowMultiple) {
|
Class<?> cls, boolean allowMultiple) {
|
||||||
mLeakChecker.addCallback(listener);
|
mLeakChecker.addCallback(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ public class FakePluginManager implements PluginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getWhitelistedPlugins() {
|
public String[] getPrivilegedPlugins() {
|
||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user