Merge "Wrap all exceptions/crashes while plugins are active" into oc-mr1-dev

am: 6bf3564040

Change-Id: Ide9a861d5db82dc8f83516ed0b340cf7468856e3
This commit is contained in:
Jason Monk
2017-08-31 18:59:28 +00:00
committed by android-build-merger
3 changed files with 31 additions and 7 deletions

View File

@@ -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.

View File

@@ -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);
}
}
}

View File

@@ -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)