Merge "Add a check to detect "duplicate app instances" bug"

This commit is contained in:
Makoto Onuki
2022-01-24 19:01:51 +00:00
committed by Android (Google) Code Review
2 changed files with 54 additions and 0 deletions

View File

@@ -29,9 +29,13 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.view.autofill.AutofillManager;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
/**
@@ -53,6 +57,10 @@ import java.util.ArrayList;
*/
public class Application extends ContextWrapper implements ComponentCallbacks2 {
private static final String TAG = "Application";
/** Whether to enable the check to detect "duplicate application instances". */
private static final boolean DEBUG_DUP_APP_INSTANCES = true;
@UnsupportedAppUsage
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
@@ -66,6 +74,13 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
@UnsupportedAppUsage
public LoadedApk mLoadedApk;
@GuardedBy("sInstances")
private static final ArrayMap<Class<?>, Application> sInstances =
DEBUG_DUP_APP_INSTANCES ? new ArrayMap<>(1) : null;
// Only set when DEBUG_DUP_APP_INSTANCES is true.
private StackTrace mConstructorStackTrace;
public interface ActivityLifecycleCallbacks {
/**
@@ -231,6 +246,41 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
public Application() {
super(null);
if (DEBUG_DUP_APP_INSTANCES) {
checkDuplicateInstances();
}
}
private void checkDuplicateInstances() {
final Class<?> myClass = this.getClass();
// We only activate this check for custom application classes.
// Otherwise, it'd misfire if multiple apps share the same process, if all of them use
// the same Application class (on the same classloader).
if (myClass == Application.class) {
return;
}
synchronized (sInstances) {
final Application firstInstance = sInstances.get(myClass);
if (firstInstance == null) {
this.mConstructorStackTrace = new StackTrace("First ctor was called here");
sInstances.put(myClass, this);
return;
}
final StackTrace currentStackTrace = new StackTrace("Current ctor was called here",
firstInstance.mConstructorStackTrace);
this.mConstructorStackTrace = currentStackTrace;
Slog.wtf(TAG, "Application ctor called twice for " + myClass
+ " first LoadedApk=" + firstInstance.getLoadedApkInfo(),
currentStackTrace);
}
}
private String getLoadedApkInfo() {
if (mLoadedApk == null) {
return "null";
}
return mLoadedApk + "/pkg=" + mLoadedApk.mPackageName;
}
/**

View File

@@ -24,4 +24,8 @@ public class StackTrace extends Exception {
public StackTrace(String message) {
super(message);
}
public StackTrace(String message, Throwable innerStackTrace) {
super(message, innerStackTrace);
}
}