From 18005c149684642b5fbc0979201e31a1708eecd8 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Thu, 20 Jan 2022 07:54:21 -0800 Subject: [PATCH] Add a check to detect "duplicate app instances" bug Test: Boot Test: Added debug code to induce the WTF situation, booted and checked the log Bug: 185177290 Change-Id: Ie95164f2794b461115f07d02c2363fbdc9a517b4 --- core/java/android/app/Application.java | 50 ++++++++++++++++++++++++++ core/java/android/app/StackTrace.java | 4 +++ 2 files changed, 54 insertions(+) diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java index 7f849ef00d7d9..9eb3e8fb0160c 100644 --- a/core/java/android/app/Application.java +++ b/core/java/android/app/Application.java @@ -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 mActivityLifecycleCallbacks = new ArrayList(); @@ -66,6 +74,13 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 { @UnsupportedAppUsage public LoadedApk mLoadedApk; + @GuardedBy("sInstances") + private static final ArrayMap, 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; } /** diff --git a/core/java/android/app/StackTrace.java b/core/java/android/app/StackTrace.java index ec058f88118bc..6a77abdefea9b 100644 --- a/core/java/android/app/StackTrace.java +++ b/core/java/android/app/StackTrace.java @@ -24,4 +24,8 @@ public class StackTrace extends Exception { public StackTrace(String message) { super(message); } + + public StackTrace(String message, Throwable innerStackTrace) { + super(message, innerStackTrace); + } }