Merge "Wrap all exceptions/crashes while plugins are active" into oc-mr1-dev
This commit is contained in:
@@ -136,11 +136,12 @@ public class PluginInstanceManager<T extends Plugin> {
|
||||
return disableAny;
|
||||
}
|
||||
|
||||
public void disableAll() {
|
||||
public boolean disableAll() {
|
||||
ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
|
||||
for (int i = 0; i < plugins.size(); i++) {
|
||||
disable(plugins.get(i));
|
||||
}
|
||||
return plugins.size() != 0;
|
||||
}
|
||||
|
||||
private void disable(PluginInfo info) {
|
||||
@@ -182,6 +183,7 @@ public class PluginInstanceManager<T extends Plugin> {
|
||||
if (DEBUG) Log.d(TAG, "onPluginConnected");
|
||||
PluginPrefs.setHasPlugins(mContext);
|
||||
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
|
||||
mManager.handleWtfs();
|
||||
if (!(msg.obj instanceof PluginFragment)) {
|
||||
// Only call onDestroy for plugins that aren't fragments, as fragments
|
||||
// will get the onCreate as part of the fragment lifecycle.
|
||||
|
||||
@@ -36,6 +36,9 @@ import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Log.TerribleFailure;
|
||||
import android.util.Log.TerribleFailureHandler;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -71,10 +74,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
||||
private boolean mListening;
|
||||
private boolean mHasOneShot;
|
||||
private Looper mLooper;
|
||||
private boolean mWtfsSet;
|
||||
|
||||
public PluginManagerImpl(Context context) {
|
||||
this(context, new PluginInstanceManagerFactory(),
|
||||
Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler());
|
||||
Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -88,7 +92,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
||||
|
||||
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
|
||||
defaultHandler);
|
||||
Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
|
||||
Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
|
||||
if (isDebuggable) {
|
||||
new Handler(mLooper).post(() -> {
|
||||
// Plugin dependencies that don't have another good home can go here, but
|
||||
@@ -290,6 +294,15 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
||||
return false;
|
||||
}
|
||||
|
||||
public void handleWtfs() {
|
||||
if (!mWtfsSet) {
|
||||
mWtfsSet = true;
|
||||
Log.setWtfHandler((tag, what, system) -> {
|
||||
throw new CrashWhilePluginActiveException(what);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static class PluginInstanceManagerFactory {
|
||||
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
|
||||
@@ -339,9 +352,12 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
||||
// disable all the plugins, so we can be sure that SysUI is running as
|
||||
// best as possible.
|
||||
for (PluginInstanceManager manager : mPluginMap.values()) {
|
||||
manager.disableAll();
|
||||
disabledAny |= manager.disableAll();
|
||||
}
|
||||
}
|
||||
if (disabledAny) {
|
||||
throwable = new CrashWhilePluginActiveException(throwable);
|
||||
}
|
||||
|
||||
// Run the normal exception handler so we can crash and cleanup our state.
|
||||
mHandler.uncaughtException(thread, throwable);
|
||||
@@ -358,4 +374,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
|
||||
return disabledAny | checkStack(throwable.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private class CrashWhilePluginActiveException extends RuntimeException {
|
||||
public CrashWhilePluginActiveException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class PluginManagerTest extends SysuiTestCase {
|
||||
public void setup() throws Exception {
|
||||
mDependency.injectTestDependency(Dependency.BG_LOOPER,
|
||||
TestableLooper.get(this).getLooper());
|
||||
mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler();
|
||||
mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
|
||||
mMockFactory = mock(PluginInstanceManagerFactory.class);
|
||||
mMockPluginInstance = mock(PluginInstanceManager.class);
|
||||
@@ -167,9 +167,9 @@ public class PluginManagerTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
private void resetExceptionHandler() {
|
||||
mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
mPluginExceptionHandler = Thread.getUncaughtExceptionPreHandler();
|
||||
// Set back the real exception handler so the test can crash if it wants to.
|
||||
Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler);
|
||||
Thread.setUncaughtExceptionPreHandler(mRealExceptionHandler);
|
||||
}
|
||||
|
||||
@ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
|
||||
|
||||
Reference in New Issue
Block a user